1 // 2 // require.hpp 3 // ~~~~~~~~~~~ 4 // 5 // Copyright (c) 2003-2020 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_REQUIRE_HPP 12 #define BOOST_ASIO_REQUIRE_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/require_member.hpp> 22 #include <boost/asio/traits/require_free.hpp> 23 #include <boost/asio/traits/static_require.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 applies a concept-preserving property to an 33 /// object. 34 /** 35 * The name <tt>require</tt> denotes a customisation point object. The 36 * expression <tt>boost::asio::require(E, P0, Pn...)</tt> for some 37 * subexpressions <tt>E</tt> and <tt>P0</tt>, and where <tt>Pn...</tt> 38 * represents <tt>N</tt> subexpressions (where <tt>N</tt> is 0 or more, and with 39 * types <tt>T = decay_t<decltype(E)></tt> and <tt>Prop0 = 40 * decay_t<decltype(P0)></tt>) is expression-equivalent to: 41 * 42 * @li If <tt>is_applicable_property_v<T, Prop0> && Prop0::is_requirable</tt> is 43 * not a well-formed constant expression with value <tt>true</tt>, 44 * <tt>boost::asio::require(E, P0, Pn...)</tt> is ill-formed. 45 * 46 * @li Otherwise, <tt>E</tt> if <tt>N == 0</tt> and the expression 47 * <tt>Prop0::template static_query_v<T> == Prop0::value()</tt> is a 48 * well-formed constant expression with value <tt>true</tt>. 49 * 50 * @li Otherwise, <tt>(E).require(P0)</tt> if <tt>N == 0</tt> and the expression 51 * <tt>(E).require(P0)</tt> is a valid expression. 52 * 53 * @li Otherwise, <tt>require(E, P0)</tt> if <tt>N == 0</tt> and the expression 54 * <tt>require(E, P0)</tt> is a valid expression with overload resolution 55 * performed in a context that does not include the declaration of the 56 * <tt>require</tt> customization point object. 57 * 58 * @li Otherwise, 59 * <tt>boost::asio::require(boost::asio::require(E, P0), Pn...)</tt> 60 * if <tt>N > 0</tt> and the expression 61 * <tt>boost::asio::require(boost::asio::require(E, P0), Pn...)</tt> 62 * is a valid expression. 63 * 64 * @li Otherwise, <tt>boost::asio::require(E, P0, Pn...)</tt> is ill-formed. 65 */ 66 inline constexpr unspecified require = unspecified; 67 68 /// A type trait that determines whether a @c require expression is well-formed. 69 /** 70 * Class template @c can_require is a trait that is derived from 71 * @c true_type if the expression <tt>boost::asio::require(std::declval<T>(), 72 * std::declval<Properties>()...)</tt> is well formed; otherwise @c false_type. 73 */ 74 template <typename T, typename... Properties> 75 struct can_require : 76 integral_constant<bool, automatically_determined> 77 { 78 }; 79 80 /// A type trait that determines whether a @c require expression will not throw. 81 /** 82 * Class template @c is_nothrow_require is a trait that is derived from 83 * @c true_type if the expression <tt>boost::asio::require(std::declval<T>(), 84 * std::declval<Properties>()...)</tt> is @c noexcept; otherwise @c false_type. 85 */ 86 template <typename T, typename... Properties> 87 struct is_nothrow_require : 88 integral_constant<bool, automatically_determined> 89 { 90 }; 91 92 /// A type trait that determines the result type of a @c require expression. 93 /** 94 * Class template @c require_result is a trait that determines the result 95 * type of the expression <tt>boost::asio::require(std::declval<T>(), 96 * std::declval<Properties>()...)</tt>. 97 */ 98 template <typename T, typename... Properties> 99 struct require_result 100 { 101 /// The result of the @c require expression. 102 typedef automatically_determined type; 103 }; 104 105 } // namespace asio 106 } // namespace boost 107 108 #else // defined(GENERATING_DOCUMENTATION) 109 110 namespace asio_require_fn { 111 112 using boost::asio::decay; 113 using boost::asio::declval; 114 using boost::asio::enable_if; 115 using boost::asio::is_applicable_property; 116 using boost::asio::traits::require_free; 117 using boost::asio::traits::require_member; 118 using boost::asio::traits::static_require; 119 120 void require(); 121 122 enum overload_type 123 { 124 identity, 125 call_member, 126 call_free, 127 two_props, 128 n_props, 129 ill_formed 130 }; 131 132 template <typename T, typename Properties, typename = void> 133 struct call_traits 134 { 135 BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed); 136 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); 137 typedef void result_type; 138 }; 139 140 template <typename T, typename Property> 141 struct call_traits<T, void(Property), 142 typename enable_if< 143 ( 144 is_applicable_property< 145 typename decay<T>::type, 146 typename decay<Property>::type 147 >::value 148 && 149 decay<Property>::type::is_requirable 150 && 151 static_require<T, Property>::is_valid 152 ) 153 >::type> 154 { 155 BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = identity); 156 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); 157 158 #if defined(BOOST_ASIO_HAS_MOVE) 159 typedef BOOST_ASIO_MOVE_ARG(T) result_type; 160 #else // defined(BOOST_ASIO_HAS_MOVE) 161 typedef BOOST_ASIO_MOVE_ARG(typename decay<T>::type) result_type; 162 #endif // defined(BOOST_ASIO_HAS_MOVE) 163 }; 164 165 template <typename T, typename Property> 166 struct call_traits<T, void(Property), 167 typename enable_if< 168 ( 169 is_applicable_property< 170 typename decay<T>::type, 171 typename decay<Property>::type 172 >::value 173 && 174 decay<Property>::type::is_requirable 175 && 176 !static_require<T, Property>::is_valid 177 && 178 require_member<T, Property>::is_valid 179 ) 180 >::type> : 181 require_member<T, Property> 182 { 183 BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member); 184 }; 185 186 template <typename T, typename Property> 187 struct call_traits<T, void(Property), 188 typename enable_if< 189 ( 190 is_applicable_property< 191 typename decay<T>::type, 192 typename decay<Property>::type 193 >::value 194 && 195 decay<Property>::type::is_requirable 196 && 197 !static_require<T, Property>::is_valid 198 && 199 !require_member<T, Property>::is_valid 200 && 201 require_free<T, Property>::is_valid 202 ) 203 >::type> : 204 require_free<T, Property> 205 { 206 BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free); 207 }; 208 209 template <typename T, typename P0, typename P1> 210 struct call_traits<T, void(P0, P1), 211 typename enable_if< 212 call_traits<T, void(P0)>::overload != ill_formed 213 && 214 call_traits< 215 typename call_traits<T, void(P0)>::result_type, 216 void(P1) 217 >::overload != ill_formed 218 >::type> 219 { 220 BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = two_props); 221 222 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = 223 ( 224 call_traits<T, void(P0)>::is_noexcept 225 && 226 call_traits< 227 typename call_traits<T, void(P0)>::result_type, 228 void(P1) 229 >::is_noexcept 230 )); 231 232 typedef typename decay< 233 typename call_traits< 234 typename call_traits<T, void(P0)>::result_type, 235 void(P1) 236 >::result_type 237 >::type result_type; 238 }; 239 240 template <typename T, typename P0, typename P1, typename BOOST_ASIO_ELLIPSIS PN> 241 struct call_traits<T, void(P0, P1, PN BOOST_ASIO_ELLIPSIS), 242 typename enable_if< 243 call_traits<T, void(P0)>::overload != ill_formed 244 && 245 call_traits< 246 typename call_traits<T, void(P0)>::result_type, 247 void(P1, PN BOOST_ASIO_ELLIPSIS) 248 >::overload != ill_formed 249 >::type> 250 { 251 BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = n_props); 252 253 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = 254 ( 255 call_traits<T, void(P0)>::is_noexcept 256 && 257 call_traits< 258 typename call_traits<T, void(P0)>::result_type, 259 void(P1, PN BOOST_ASIO_ELLIPSIS) 260 >::is_noexcept 261 )); 262 263 typedef typename decay< 264 typename call_traits< 265 typename call_traits<T, void(P0)>::result_type, 266 void(P1, PN BOOST_ASIO_ELLIPSIS) 267 >::result_type 268 >::type result_type; 269 }; 270 271 struct impl 272 { 273 template <typename T, typename Property> 274 BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if< 275 call_traits<T, void(Property)>::overload == identity, 276 typename call_traits<T, void(Property)>::result_type 277 >::type operator ()asio_require_fn::impl278 operator()( 279 BOOST_ASIO_MOVE_ARG(T) t, 280 BOOST_ASIO_MOVE_ARG(Property)) const 281 BOOST_ASIO_NOEXCEPT_IF(( 282 call_traits<T, void(Property)>::is_noexcept)) 283 { 284 return BOOST_ASIO_MOVE_CAST(T)(t); 285 } 286 287 template <typename T, typename Property> 288 BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if< 289 call_traits<T, void(Property)>::overload == call_member, 290 typename call_traits<T, void(Property)>::result_type 291 >::type operator ()asio_require_fn::impl292 operator()( 293 BOOST_ASIO_MOVE_ARG(T) t, 294 BOOST_ASIO_MOVE_ARG(Property) p) const 295 BOOST_ASIO_NOEXCEPT_IF(( 296 call_traits<T, void(Property)>::is_noexcept)) 297 { 298 return BOOST_ASIO_MOVE_CAST(T)(t).require( 299 BOOST_ASIO_MOVE_CAST(Property)(p)); 300 } 301 302 template <typename T, typename Property> 303 BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if< 304 call_traits<T, void(Property)>::overload == call_free, 305 typename call_traits<T, void(Property)>::result_type 306 >::type operator ()asio_require_fn::impl307 operator()( 308 BOOST_ASIO_MOVE_ARG(T) t, 309 BOOST_ASIO_MOVE_ARG(Property) p) const 310 BOOST_ASIO_NOEXCEPT_IF(( 311 call_traits<T, void(Property)>::is_noexcept)) 312 { 313 return require( 314 BOOST_ASIO_MOVE_CAST(T)(t), 315 BOOST_ASIO_MOVE_CAST(Property)(p)); 316 } 317 318 template <typename T, typename P0, typename P1> 319 BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if< 320 call_traits<T, void(P0, P1)>::overload == two_props, 321 typename call_traits<T, void(P0, P1)>::result_type 322 >::type operator ()asio_require_fn::impl323 operator()( 324 BOOST_ASIO_MOVE_ARG(T) t, 325 BOOST_ASIO_MOVE_ARG(P0) p0, 326 BOOST_ASIO_MOVE_ARG(P1) p1) const 327 BOOST_ASIO_NOEXCEPT_IF(( 328 call_traits<T, void(P0, P1)>::is_noexcept)) 329 { 330 return (*this)( 331 (*this)( 332 BOOST_ASIO_MOVE_CAST(T)(t), 333 BOOST_ASIO_MOVE_CAST(P0)(p0)), 334 BOOST_ASIO_MOVE_CAST(P1)(p1)); 335 } 336 337 template <typename T, typename P0, typename P1, 338 typename BOOST_ASIO_ELLIPSIS PN> 339 BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if< 340 call_traits<T, void(P0, P1, PN BOOST_ASIO_ELLIPSIS)>::overload == n_props, 341 typename call_traits<T, void(P0, P1, PN BOOST_ASIO_ELLIPSIS)>::result_type 342 >::type operator ()asio_require_fn::impl343 operator()( 344 BOOST_ASIO_MOVE_ARG(T) t, 345 BOOST_ASIO_MOVE_ARG(P0) p0, 346 BOOST_ASIO_MOVE_ARG(P1) p1, 347 BOOST_ASIO_MOVE_ARG(PN) BOOST_ASIO_ELLIPSIS pn) const 348 BOOST_ASIO_NOEXCEPT_IF(( 349 call_traits<T, void(P0, P1, PN BOOST_ASIO_ELLIPSIS)>::is_noexcept)) 350 { 351 return (*this)( 352 (*this)( 353 BOOST_ASIO_MOVE_CAST(T)(t), 354 BOOST_ASIO_MOVE_CAST(P0)(p0)), 355 BOOST_ASIO_MOVE_CAST(P1)(p1), 356 BOOST_ASIO_MOVE_CAST(PN)(pn) BOOST_ASIO_ELLIPSIS); 357 } 358 }; 359 360 template <typename T = impl> 361 struct static_instance 362 { 363 static const T instance; 364 }; 365 366 template <typename T> 367 const T static_instance<T>::instance = {}; 368 369 } // namespace asio_require_fn 370 namespace boost { 371 namespace asio { 372 namespace { 373 374 static BOOST_ASIO_CONSTEXPR const asio_require_fn::impl& 375 require = asio_require_fn::static_instance<>::instance; 376 377 } // namespace 378 379 #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) 380 381 template <typename T, typename... Properties> 382 struct can_require : 383 integral_constant<bool, 384 asio_require_fn::call_traits<T, void(Properties...)>::overload 385 != asio_require_fn::ill_formed> 386 { 387 }; 388 389 #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) 390 391 template <typename T, typename P0 = void, 392 typename P1 = void, typename P2 = void> 393 struct can_require : 394 integral_constant<bool, 395 asio_require_fn::call_traits<T, void(P0, P1, P2)>::overload 396 != asio_require_fn::ill_formed> 397 { 398 }; 399 400 template <typename T, typename P0, typename P1> 401 struct can_require<T, P0, P1> : 402 integral_constant<bool, 403 asio_require_fn::call_traits<T, void(P0, P1)>::overload 404 != asio_require_fn::ill_formed> 405 { 406 }; 407 408 template <typename T, typename P0> 409 struct can_require<T, P0> : 410 integral_constant<bool, 411 asio_require_fn::call_traits<T, void(P0)>::overload 412 != asio_require_fn::ill_formed> 413 { 414 }; 415 416 template <typename T> 417 struct can_require<T> : 418 false_type 419 { 420 }; 421 422 #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) 423 424 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) 425 426 template <typename T, typename BOOST_ASIO_ELLIPSIS Properties> 427 constexpr bool can_require_v 428 = can_require<T, Properties BOOST_ASIO_ELLIPSIS>::value; 429 430 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) 431 432 #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) 433 434 template <typename T, typename... Properties> 435 struct is_nothrow_require : 436 integral_constant<bool, 437 asio_require_fn::call_traits<T, void(Properties...)>::is_noexcept> 438 { 439 }; 440 441 #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) 442 443 template <typename T, typename P0 = void, 444 typename P1 = void, typename P2 = void> 445 struct is_nothrow_require : 446 integral_constant<bool, 447 asio_require_fn::call_traits<T, void(P0, P1, P2)>::is_noexcept> 448 { 449 }; 450 451 template <typename T, typename P0, typename P1> 452 struct is_nothrow_require<T, P0, P1> : 453 integral_constant<bool, 454 asio_require_fn::call_traits<T, void(P0, P1)>::is_noexcept> 455 { 456 }; 457 458 template <typename T, typename P0> 459 struct is_nothrow_require<T, P0> : 460 integral_constant<bool, 461 asio_require_fn::call_traits<T, void(P0)>::is_noexcept> 462 { 463 }; 464 465 template <typename T> 466 struct is_nothrow_require<T> : 467 false_type 468 { 469 }; 470 471 #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) 472 473 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) 474 475 template <typename T, typename BOOST_ASIO_ELLIPSIS Properties> 476 constexpr bool is_nothrow_require_v 477 = is_nothrow_require<T, Properties BOOST_ASIO_ELLIPSIS>::value; 478 479 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) 480 481 #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) 482 483 template <typename T, typename... Properties> 484 struct require_result 485 { 486 typedef typename asio_require_fn::call_traits< 487 T, void(Properties...)>::result_type type; 488 }; 489 490 #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) 491 492 template <typename T, typename P0 = void, 493 typename P1 = void, typename P2 = void> 494 struct require_result 495 { 496 typedef typename asio_require_fn::call_traits< 497 T, void(P0, P1, P2)>::result_type type; 498 }; 499 500 template <typename T, typename P0, typename P1> 501 struct require_result<T, P0, P1> 502 { 503 typedef typename asio_require_fn::call_traits< 504 T, void(P0, P1)>::result_type type; 505 }; 506 507 template <typename T, typename P0> 508 struct require_result<T, P0> 509 { 510 typedef typename asio_require_fn::call_traits< 511 T, void(P0)>::result_type type; 512 }; 513 514 template <typename T> 515 struct require_result<T> 516 { 517 }; 518 519 #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) 520 521 } // namespace asio 522 } // namespace boost 523 524 #endif // defined(GENERATING_DOCUMENTATION) 525 526 #include <boost/asio/detail/pop_options.hpp> 527 528 #endif // BOOST_ASIO_REQUIRE_HPP 529