1 // 2 // query.hpp 3 // ~~~~~~~~~ 4 // 5 // Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6 // 7 // Distributed under the Boost Software License, Version 1.0. (See accompanying 8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 // 10 11 #ifndef BOOST_ASIO_QUERY_HPP 12 #define BOOST_ASIO_QUERY_HPP 13 14 #if defined(_MSC_VER) && (_MSC_VER >= 1200) 15 # pragma once 16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) 17 18 #include <boost/asio/detail/config.hpp> 19 #include <boost/asio/detail/type_traits.hpp> 20 #include <boost/asio/is_applicable_property.hpp> 21 #include <boost/asio/traits/query_member.hpp> 22 #include <boost/asio/traits/query_free.hpp> 23 #include <boost/asio/traits/static_query.hpp> 24 25 #include <boost/asio/detail/push_options.hpp> 26 27 #if defined(GENERATING_DOCUMENTATION) 28 29 namespace boost { 30 namespace asio { 31 32 /// A customisation point that queries the value of a property. 33 /** 34 * The name <tt>query</tt> denotes a customization point object. The 35 * expression <tt>boost::asio::query(E, P)</tt> for some 36 * subexpressions <tt>E</tt> and <tt>P</tt> (with types <tt>T = 37 * decay_t<decltype(E)></tt> and <tt>Prop = decay_t<decltype(P)></tt>) is 38 * expression-equivalent to: 39 * 40 * @li If <tt>is_applicable_property_v<T, Prop></tt> is not a well-formed 41 * constant expression with value <tt>true</tt>, <tt>boost::asio::query(E, 42 * P)</tt> is ill-formed. 43 * 44 * @li Otherwise, <tt>Prop::template static_query_v<T></tt> if the expression 45 * <tt>Prop::template static_query_v<T></tt> is a well-formed constant 46 * expression. 47 * 48 * @li Otherwise, <tt>(E).query(P)</tt> if the expression 49 * <tt>(E).query(P)</tt> is well-formed. 50 * 51 * @li Otherwise, <tt>query(E, P)</tt> if the expression 52 * <tt>query(E, P)</tt> is a valid expression with overload 53 * resolution performed in a context that does not include the declaration 54 * of the <tt>query</tt> customization point object. 55 * 56 * @li Otherwise, <tt>boost::asio::query(E, P)</tt> is ill-formed. 57 */ 58 inline constexpr unspecified query = unspecified; 59 60 /// A type trait that determines whether a @c query expression is well-formed. 61 /** 62 * Class template @c can_query is a trait that is derived from 63 * @c true_type if the expression <tt>boost::asio::query(std::declval<T>(), 64 * std::declval<Property>())</tt> is well formed; otherwise @c false_type. 65 */ 66 template <typename T, typename Property> 67 struct can_query : 68 integral_constant<bool, automatically_determined> 69 { 70 }; 71 72 /// A type trait that determines whether a @c query expression will 73 /// not throw. 74 /** 75 * Class template @c is_nothrow_query is a trait that is derived from 76 * @c true_type if the expression <tt>boost::asio::query(std::declval<T>(), 77 * std::declval<Property>())</tt> is @c noexcept; otherwise @c false_type. 78 */ 79 template <typename T, typename Property> 80 struct is_nothrow_query : 81 integral_constant<bool, automatically_determined> 82 { 83 }; 84 85 /// A type trait that determines the result type of a @c query expression. 86 /** 87 * Class template @c query_result is a trait that determines the result 88 * type of the expression <tt>boost::asio::query(std::declval<T>(), 89 * std::declval<Property>())</tt>. 90 */ 91 template <typename T, typename Property> 92 struct query_result 93 { 94 /// The result of the @c query expression. 95 typedef automatically_determined type; 96 }; 97 98 } // namespace asio 99 } // namespace boost 100 101 #else // defined(GENERATING_DOCUMENTATION) 102 103 namespace asio_query_fn { 104 105 using boost::asio::conditional; 106 using boost::asio::decay; 107 using boost::asio::declval; 108 using boost::asio::enable_if; 109 using boost::asio::is_applicable_property; 110 using boost::asio::traits::query_free; 111 using boost::asio::traits::query_member; 112 using boost::asio::traits::static_query; 113 114 void query(); 115 116 enum overload_type 117 { 118 static_value, 119 call_member, 120 call_free, 121 ill_formed 122 }; 123 124 template <typename Impl, typename T, typename Properties, 125 typename = void, typename = void, typename = void, typename = void> 126 struct call_traits 127 { 128 BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed); 129 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); 130 typedef void result_type; 131 }; 132 133 template <typename Impl, typename T, typename Property> 134 struct call_traits<Impl, T, void(Property), 135 typename enable_if< 136 is_applicable_property< 137 typename decay<T>::type, 138 typename decay<Property>::type 139 >::value 140 >::type, 141 typename enable_if< 142 static_query<T, Property>::is_valid 143 >::type> : 144 static_query<T, Property> 145 { 146 BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = static_value); 147 }; 148 149 template <typename Impl, typename T, typename Property> 150 struct call_traits<Impl, T, void(Property), 151 typename enable_if< 152 is_applicable_property< 153 typename decay<T>::type, 154 typename decay<Property>::type 155 >::value 156 >::type, 157 typename enable_if< 158 !static_query<T, Property>::is_valid 159 >::type, 160 typename enable_if< 161 query_member<typename Impl::template proxy<T>::type, Property>::is_valid 162 >::type> : 163 query_member<typename Impl::template proxy<T>::type, Property> 164 { 165 BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member); 166 }; 167 168 template <typename Impl, typename T, typename Property> 169 struct call_traits<Impl, T, void(Property), 170 typename enable_if< 171 is_applicable_property< 172 typename decay<T>::type, 173 typename decay<Property>::type 174 >::value 175 >::type, 176 typename enable_if< 177 !static_query<T, Property>::is_valid 178 >::type, 179 typename enable_if< 180 !query_member<typename Impl::template proxy<T>::type, Property>::is_valid 181 >::type, 182 typename enable_if< 183 query_free<T, Property>::is_valid 184 >::type> : 185 query_free<T, Property> 186 { 187 BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free); 188 }; 189 190 struct impl 191 { 192 template <typename T> 193 struct proxy 194 { 195 #if defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) 196 struct type 197 { 198 template <typename P> 199 auto query(BOOST_ASIO_MOVE_ARG(P) p) 200 noexcept( 201 noexcept( 202 declval<typename conditional<true, T, P>::type>().query( 203 BOOST_ASIO_MOVE_CAST(P)(p)) 204 ) 205 ) 206 -> decltype( 207 declval<typename conditional<true, T, P>::type>().query( 208 BOOST_ASIO_MOVE_CAST(P)(p)) 209 ); 210 }; 211 #else // defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) 212 typedef T type; 213 #endif // defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) 214 }; 215 216 template <typename T, typename Property> 217 BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if< 218 call_traits<impl, T, void(Property)>::overload == static_value, 219 typename call_traits<impl, T, void(Property)>::result_type 220 >::type operator ()asio_query_fn::impl221 operator()( 222 BOOST_ASIO_MOVE_ARG(T), 223 BOOST_ASIO_MOVE_ARG(Property)) const 224 BOOST_ASIO_NOEXCEPT_IF(( 225 call_traits<impl, T, void(Property)>::is_noexcept)) 226 { 227 return static_query< 228 typename decay<T>::type, 229 typename decay<Property>::type 230 >::value(); 231 } 232 233 template <typename T, typename Property> 234 BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if< 235 call_traits<impl, T, void(Property)>::overload == call_member, 236 typename call_traits<impl, T, void(Property)>::result_type 237 >::type operator ()asio_query_fn::impl238 operator()( 239 BOOST_ASIO_MOVE_ARG(T) t, 240 BOOST_ASIO_MOVE_ARG(Property) p) const 241 BOOST_ASIO_NOEXCEPT_IF(( 242 call_traits<impl, T, void(Property)>::is_noexcept)) 243 { 244 return BOOST_ASIO_MOVE_CAST(T)(t).query(BOOST_ASIO_MOVE_CAST(Property)(p)); 245 } 246 247 template <typename T, typename Property> 248 BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if< 249 call_traits<impl, T, void(Property)>::overload == call_free, 250 typename call_traits<impl, T, void(Property)>::result_type 251 >::type operator ()asio_query_fn::impl252 operator()( 253 BOOST_ASIO_MOVE_ARG(T) t, 254 BOOST_ASIO_MOVE_ARG(Property) p) const 255 BOOST_ASIO_NOEXCEPT_IF(( 256 call_traits<impl, T, void(Property)>::is_noexcept)) 257 { 258 return query(BOOST_ASIO_MOVE_CAST(T)(t), BOOST_ASIO_MOVE_CAST(Property)(p)); 259 } 260 }; 261 262 template <typename T = impl> 263 struct static_instance 264 { 265 static const T instance; 266 }; 267 268 template <typename T> 269 const T static_instance<T>::instance = {}; 270 271 } // namespace asio_query_fn 272 namespace boost { 273 namespace asio { 274 namespace { 275 276 static BOOST_ASIO_CONSTEXPR const asio_query_fn::impl& 277 query = asio_query_fn::static_instance<>::instance; 278 279 } // namespace 280 281 typedef asio_query_fn::impl query_t; 282 283 template <typename T, typename Property> 284 struct can_query : 285 integral_constant<bool, 286 asio_query_fn::call_traits<query_t, T, void(Property)>::overload != 287 asio_query_fn::ill_formed> 288 { 289 }; 290 291 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) 292 293 template <typename T, typename Property> 294 constexpr bool can_query_v 295 = can_query<T, Property>::value; 296 297 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) 298 299 template <typename T, typename Property> 300 struct is_nothrow_query : 301 integral_constant<bool, 302 asio_query_fn::call_traits<query_t, T, void(Property)>::is_noexcept> 303 { 304 }; 305 306 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) 307 308 template <typename T, typename Property> 309 constexpr bool is_nothrow_query_v 310 = is_nothrow_query<T, Property>::value; 311 312 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) 313 314 template <typename T, typename Property> 315 struct query_result 316 { 317 typedef typename asio_query_fn::call_traits< 318 query_t, T, void(Property)>::result_type type; 319 }; 320 321 } // namespace asio 322 } // namespace boost 323 324 #endif // defined(GENERATING_DOCUMENTATION) 325 326 #include <boost/asio/detail/pop_options.hpp> 327 328 #endif // BOOST_ASIO_QUERY_HPP 329