require.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. //
  2. // require.hpp
  3. // ~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2023 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_t;
  97. using asio::decay_t;
  98. using asio::declval;
  99. using asio::enable_if_t;
  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. static constexpr overload_type overload = ill_formed;
  119. 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. enable_if_t<
  125. is_applicable_property<
  126. decay_t<T>,
  127. decay_t<Property>
  128. >::value
  129. >,
  130. enable_if_t<
  131. decay_t<Property>::is_requirable
  132. >,
  133. enable_if_t<
  134. static_require<T, Property>::is_valid
  135. >>
  136. {
  137. static constexpr overload_type overload = identity;
  138. static constexpr bool is_noexcept = true;
  139. typedef T&& result_type;
  140. };
  141. template <typename Impl, typename T, typename Property>
  142. struct call_traits<Impl, T, void(Property),
  143. enable_if_t<
  144. is_applicable_property<
  145. decay_t<T>,
  146. decay_t<Property>
  147. >::value
  148. >,
  149. enable_if_t<
  150. decay_t<Property>::is_requirable
  151. >,
  152. enable_if_t<
  153. !static_require<T, Property>::is_valid
  154. >,
  155. enable_if_t<
  156. require_member<typename Impl::template proxy<T>::type, Property>::is_valid
  157. >> :
  158. require_member<typename Impl::template proxy<T>::type, Property>
  159. {
  160. static constexpr overload_type overload = call_member;
  161. };
  162. template <typename Impl, typename T, typename Property>
  163. struct call_traits<Impl, T, void(Property),
  164. enable_if_t<
  165. is_applicable_property<
  166. decay_t<T>,
  167. decay_t<Property>
  168. >::value
  169. >,
  170. enable_if_t<
  171. decay_t<Property>::is_requirable
  172. >,
  173. enable_if_t<
  174. !static_require<T, Property>::is_valid
  175. >,
  176. enable_if_t<
  177. !require_member<typename Impl::template proxy<T>::type, Property>::is_valid
  178. >,
  179. enable_if_t<
  180. require_free<T, Property>::is_valid
  181. >> :
  182. require_free<T, Property>
  183. {
  184. static constexpr overload_type overload = call_free;
  185. };
  186. template <typename Impl, typename T, typename P0, typename P1>
  187. struct call_traits<Impl, T, void(P0, P1),
  188. enable_if_t<
  189. call_traits<Impl, T, void(P0)>::overload != ill_formed
  190. >,
  191. enable_if_t<
  192. call_traits<
  193. Impl,
  194. typename call_traits<Impl, T, void(P0)>::result_type,
  195. void(P1)
  196. >::overload != ill_formed
  197. >>
  198. {
  199. static constexpr overload_type overload = two_props;
  200. static constexpr bool is_noexcept =
  201. (
  202. call_traits<Impl, T, void(P0)>::is_noexcept
  203. &&
  204. call_traits<
  205. Impl,
  206. typename call_traits<Impl, T, void(P0)>::result_type,
  207. void(P1)
  208. >::is_noexcept
  209. );
  210. typedef decay_t<
  211. typename call_traits<
  212. Impl,
  213. typename call_traits<Impl, T, void(P0)>::result_type,
  214. void(P1)
  215. >::result_type
  216. > result_type;
  217. };
  218. template <typename Impl, typename T, typename P0,
  219. typename P1, typename... PN>
  220. struct call_traits<Impl, T, void(P0, P1, PN...),
  221. enable_if_t<
  222. call_traits<Impl, T, void(P0)>::overload != ill_formed
  223. >,
  224. enable_if_t<
  225. call_traits<
  226. Impl,
  227. typename call_traits<Impl, T, void(P0)>::result_type,
  228. void(P1, PN...)
  229. >::overload != ill_formed
  230. >>
  231. {
  232. static constexpr overload_type overload = n_props;
  233. static constexpr bool is_noexcept =
  234. (
  235. call_traits<Impl, T, void(P0)>::is_noexcept
  236. &&
  237. call_traits<
  238. Impl,
  239. typename call_traits<Impl, T, void(P0)>::result_type,
  240. void(P1, PN...)
  241. >::is_noexcept
  242. );
  243. typedef decay_t<
  244. typename call_traits<
  245. Impl,
  246. typename call_traits<Impl, T, void(P0)>::result_type,
  247. void(P1, PN...)
  248. >::result_type
  249. > result_type;
  250. };
  251. struct impl
  252. {
  253. template <typename T>
  254. struct proxy
  255. {
  256. #if defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
  257. struct type
  258. {
  259. template <typename P>
  260. auto require(P&& p)
  261. noexcept(
  262. noexcept(
  263. declval<conditional_t<true, T, P>>().require(static_cast<P&&>(p))
  264. )
  265. )
  266. -> decltype(
  267. declval<conditional_t<true, T, P>>().require(static_cast<P&&>(p))
  268. );
  269. };
  270. #else // defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
  271. typedef T type;
  272. #endif // defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
  273. };
  274. template <typename T, typename Property>
  275. ASIO_NODISCARD constexpr enable_if_t<
  276. call_traits<impl, T, void(Property)>::overload == identity,
  277. typename call_traits<impl, T, void(Property)>::result_type
  278. >
  279. operator()(T&& t, Property&&) const
  280. noexcept(call_traits<impl, T, void(Property)>::is_noexcept)
  281. {
  282. return static_cast<T&&>(t);
  283. }
  284. template <typename T, typename Property>
  285. ASIO_NODISCARD constexpr enable_if_t<
  286. call_traits<impl, T, void(Property)>::overload == call_member,
  287. typename call_traits<impl, T, void(Property)>::result_type
  288. >
  289. operator()(T&& t, Property&& p) const
  290. noexcept(call_traits<impl, T, void(Property)>::is_noexcept)
  291. {
  292. return static_cast<T&&>(t).require(static_cast<Property&&>(p));
  293. }
  294. template <typename T, typename Property>
  295. ASIO_NODISCARD constexpr enable_if_t<
  296. call_traits<impl, T, void(Property)>::overload == call_free,
  297. typename call_traits<impl, T, void(Property)>::result_type
  298. >
  299. operator()(T&& t, Property&& p) const
  300. noexcept(call_traits<impl, T, void(Property)>::is_noexcept)
  301. {
  302. return require(static_cast<T&&>(t), static_cast<Property&&>(p));
  303. }
  304. template <typename T, typename P0, typename P1>
  305. ASIO_NODISCARD constexpr enable_if_t<
  306. call_traits<impl, T, void(P0, P1)>::overload == two_props,
  307. typename call_traits<impl, T, void(P0, P1)>::result_type
  308. >
  309. operator()(T&& t, P0&& p0, P1&& p1) const
  310. noexcept(call_traits<impl, T, void(P0, P1)>::is_noexcept)
  311. {
  312. return (*this)(
  313. (*this)(static_cast<T&&>(t), static_cast<P0&&>(p0)),
  314. static_cast<P1&&>(p1));
  315. }
  316. template <typename T, typename P0, typename P1,
  317. typename... PN>
  318. ASIO_NODISCARD constexpr enable_if_t<
  319. call_traits<impl, T, void(P0, P1, PN...)>::overload == n_props,
  320. typename call_traits<impl, T, void(P0, P1, PN...)>::result_type
  321. >
  322. operator()(T&& t, P0&& p0, P1&& p1, PN&&... pn) const
  323. noexcept(call_traits<impl, T, void(P0, P1, PN...)>::is_noexcept)
  324. {
  325. return (*this)(
  326. (*this)(static_cast<T&&>(t), static_cast<P0&&>(p0)),
  327. static_cast<P1&&>(p1), static_cast<PN&&>(pn)...);
  328. }
  329. };
  330. template <typename T = impl>
  331. struct static_instance
  332. {
  333. static const T instance;
  334. };
  335. template <typename T>
  336. const T static_instance<T>::instance = {};
  337. } // namespace asio_require_fn
  338. namespace asio {
  339. namespace {
  340. static constexpr const asio_require_fn::impl&
  341. require = asio_require_fn::static_instance<>::instance;
  342. } // namespace
  343. typedef asio_require_fn::impl require_t;
  344. template <typename T, typename... Properties>
  345. struct can_require :
  346. integral_constant<bool,
  347. asio_require_fn::call_traits<
  348. require_t, T, void(Properties...)>::overload
  349. != asio_require_fn::ill_formed>
  350. {
  351. };
  352. #if defined(ASIO_HAS_VARIABLE_TEMPLATES)
  353. template <typename T, typename... Properties>
  354. constexpr bool can_require_v
  355. = can_require<T, Properties...>::value;
  356. #endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
  357. template <typename T, typename... Properties>
  358. struct is_nothrow_require :
  359. integral_constant<bool,
  360. asio_require_fn::call_traits<
  361. require_t, T, void(Properties...)>::is_noexcept>
  362. {
  363. };
  364. #if defined(ASIO_HAS_VARIABLE_TEMPLATES)
  365. template <typename T, typename... Properties>
  366. constexpr bool is_nothrow_require_v
  367. = is_nothrow_require<T, Properties...>::value;
  368. #endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
  369. template <typename T, typename... Properties>
  370. struct require_result
  371. {
  372. typedef typename asio_require_fn::call_traits<
  373. require_t, T, void(Properties...)>::result_type type;
  374. };
  375. template <typename T, typename... Properties>
  376. using require_result_t = typename require_result<T, Properties...>::type;
  377. } // namespace asio
  378. #endif // defined(GENERATING_DOCUMENTATION)
  379. #include "asio/detail/pop_options.hpp"
  380. #endif // ASIO_REQUIRE_HPP