require.hpp 15 KB

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