require.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. //
  2. // require.hpp
  3. // ~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2024 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 BOOST_ASIO_REQUIRE_HPP
  11. #define BOOST_ASIO_REQUIRE_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <boost/asio/detail/config.hpp>
  16. #include <boost/asio/detail/type_traits.hpp>
  17. #include <boost/asio/is_applicable_property.hpp>
  18. #include <boost/asio/traits/require_member.hpp>
  19. #include <boost/asio/traits/require_free.hpp>
  20. #include <boost/asio/traits/static_require.hpp>
  21. #include <boost/asio/detail/push_options.hpp>
  22. #if defined(GENERATING_DOCUMENTATION)
  23. namespace boost {
  24. namespace asio {
  25. /// A customisation point that applies a concept-preserving property to an
  26. /// object.
  27. /**
  28. * The name <tt>require</tt> denotes a customisation point object. The
  29. * expression <tt>boost::asio::require(E, P0, Pn...)</tt> for some
  30. * subexpressions <tt>E</tt> and <tt>P0</tt>, and where <tt>Pn...</tt>
  31. * represents <tt>N</tt> subexpressions (where <tt>N</tt> is 0 or more, and with
  32. * types <tt>T = decay_t<decltype(E)></tt> and <tt>Prop0 =
  33. * decay_t<decltype(P0)></tt>) is expression-equivalent to:
  34. *
  35. * @li If <tt>is_applicable_property_v<T, Prop0> && Prop0::is_requirable</tt> is
  36. * not a well-formed constant expression with value <tt>true</tt>,
  37. * <tt>boost::asio::require(E, P0, Pn...)</tt> is ill-formed.
  38. *
  39. * @li Otherwise, <tt>E</tt> if <tt>N == 0</tt> and the expression
  40. * <tt>Prop0::template static_query_v<T> == Prop0::value()</tt> is a
  41. * well-formed constant expression with value <tt>true</tt>.
  42. *
  43. * @li Otherwise, <tt>(E).require(P0)</tt> if <tt>N == 0</tt> and the expression
  44. * <tt>(E).require(P0)</tt> is a valid expression.
  45. *
  46. * @li Otherwise, <tt>require(E, P0)</tt> if <tt>N == 0</tt> and the expression
  47. * <tt>require(E, P0)</tt> is a valid expression with overload resolution
  48. * performed in a context that does not include the declaration of the
  49. * <tt>require</tt> customization point object.
  50. *
  51. * @li Otherwise,
  52. * <tt>boost::asio::require(boost::asio::require(E, P0), Pn...)</tt>
  53. * if <tt>N > 0</tt> and the expression
  54. * <tt>boost::asio::require(boost::asio::require(E, P0), Pn...)</tt>
  55. * is a valid expression.
  56. *
  57. * @li Otherwise, <tt>boost::asio::require(E, P0, Pn...)</tt> is ill-formed.
  58. */
  59. inline constexpr unspecified require = unspecified;
  60. /// A type trait that determines whether a @c require expression is well-formed.
  61. /**
  62. * Class template @c can_require is a trait that is derived from
  63. * @c true_type if the expression <tt>boost::asio::require(std::declval<T>(),
  64. * std::declval<Properties>()...)</tt> is well formed; otherwise @c false_type.
  65. */
  66. template <typename T, typename... Properties>
  67. struct can_require :
  68. integral_constant<bool, automatically_determined>
  69. {
  70. };
  71. /// A type trait that determines whether a @c require expression will not throw.
  72. /**
  73. * Class template @c is_nothrow_require is a trait that is derived from
  74. * @c true_type if the expression <tt>boost::asio::require(std::declval<T>(),
  75. * std::declval<Properties>()...)</tt> is @c noexcept; otherwise @c false_type.
  76. */
  77. template <typename T, typename... Properties>
  78. struct is_nothrow_require :
  79. integral_constant<bool, automatically_determined>
  80. {
  81. };
  82. /// A type trait that determines the result type of a @c require expression.
  83. /**
  84. * Class template @c require_result is a trait that determines the result
  85. * type of the expression <tt>boost::asio::require(std::declval<T>(),
  86. * std::declval<Properties>()...)</tt>.
  87. */
  88. template <typename T, typename... Properties>
  89. struct require_result
  90. {
  91. /// The result of the @c require expression.
  92. typedef automatically_determined type;
  93. };
  94. } // namespace asio
  95. } // namespace boost
  96. #else // defined(GENERATING_DOCUMENTATION)
  97. namespace boost_asio_require_fn {
  98. using boost::asio::conditional_t;
  99. using boost::asio::decay_t;
  100. using boost::asio::declval;
  101. using boost::asio::enable_if_t;
  102. using boost::asio::is_applicable_property;
  103. using boost::asio::traits::require_free;
  104. using boost::asio::traits::require_member;
  105. using boost::asio::traits::static_require;
  106. void require();
  107. enum overload_type
  108. {
  109. identity,
  110. call_member,
  111. call_free,
  112. two_props,
  113. n_props,
  114. ill_formed
  115. };
  116. template <typename Impl, typename T, typename Properties, typename = void,
  117. typename = void, typename = void, typename = void, typename = void>
  118. struct call_traits
  119. {
  120. static constexpr overload_type overload = ill_formed;
  121. static constexpr bool is_noexcept = false;
  122. typedef void result_type;
  123. };
  124. template <typename Impl, typename T, typename Property>
  125. struct call_traits<Impl, T, void(Property),
  126. enable_if_t<
  127. is_applicable_property<
  128. decay_t<T>,
  129. decay_t<Property>
  130. >::value
  131. >,
  132. enable_if_t<
  133. decay_t<Property>::is_requirable
  134. >,
  135. enable_if_t<
  136. static_require<T, Property>::is_valid
  137. >>
  138. {
  139. static constexpr overload_type overload = identity;
  140. static constexpr bool is_noexcept = true;
  141. typedef T&& result_type;
  142. };
  143. template <typename Impl, typename T, typename Property>
  144. struct call_traits<Impl, T, void(Property),
  145. enable_if_t<
  146. is_applicable_property<
  147. decay_t<T>,
  148. decay_t<Property>
  149. >::value
  150. >,
  151. enable_if_t<
  152. decay_t<Property>::is_requirable
  153. >,
  154. enable_if_t<
  155. !static_require<T, Property>::is_valid
  156. >,
  157. enable_if_t<
  158. require_member<typename Impl::template proxy<T>::type, Property>::is_valid
  159. >> :
  160. require_member<typename Impl::template proxy<T>::type, Property>
  161. {
  162. static constexpr overload_type overload = call_member;
  163. };
  164. template <typename Impl, typename T, typename Property>
  165. struct call_traits<Impl, T, void(Property),
  166. enable_if_t<
  167. is_applicable_property<
  168. decay_t<T>,
  169. decay_t<Property>
  170. >::value
  171. >,
  172. enable_if_t<
  173. decay_t<Property>::is_requirable
  174. >,
  175. enable_if_t<
  176. !static_require<T, Property>::is_valid
  177. >,
  178. enable_if_t<
  179. !require_member<typename Impl::template proxy<T>::type, Property>::is_valid
  180. >,
  181. enable_if_t<
  182. require_free<T, Property>::is_valid
  183. >> :
  184. require_free<T, Property>
  185. {
  186. static constexpr overload_type overload = call_free;
  187. };
  188. template <typename Impl, typename T, typename P0, typename P1>
  189. struct call_traits<Impl, T, void(P0, P1),
  190. enable_if_t<
  191. call_traits<Impl, T, void(P0)>::overload != ill_formed
  192. >,
  193. enable_if_t<
  194. call_traits<
  195. Impl,
  196. typename call_traits<Impl, T, void(P0)>::result_type,
  197. void(P1)
  198. >::overload != ill_formed
  199. >>
  200. {
  201. static constexpr overload_type overload = two_props;
  202. static constexpr bool is_noexcept =
  203. (
  204. call_traits<Impl, T, void(P0)>::is_noexcept
  205. &&
  206. call_traits<
  207. Impl,
  208. typename call_traits<Impl, T, void(P0)>::result_type,
  209. void(P1)
  210. >::is_noexcept
  211. );
  212. typedef decay_t<
  213. typename call_traits<
  214. Impl,
  215. typename call_traits<Impl, T, void(P0)>::result_type,
  216. void(P1)
  217. >::result_type
  218. > result_type;
  219. };
  220. template <typename Impl, typename T, typename P0,
  221. typename P1, typename... PN>
  222. struct call_traits<Impl, T, void(P0, P1, PN...),
  223. enable_if_t<
  224. call_traits<Impl, T, void(P0)>::overload != ill_formed
  225. >,
  226. enable_if_t<
  227. call_traits<
  228. Impl,
  229. typename call_traits<Impl, T, void(P0)>::result_type,
  230. void(P1, PN...)
  231. >::overload != ill_formed
  232. >>
  233. {
  234. static constexpr overload_type overload = n_props;
  235. static constexpr bool is_noexcept =
  236. (
  237. call_traits<Impl, T, void(P0)>::is_noexcept
  238. &&
  239. call_traits<
  240. Impl,
  241. typename call_traits<Impl, T, void(P0)>::result_type,
  242. void(P1, PN...)
  243. >::is_noexcept
  244. );
  245. typedef decay_t<
  246. typename call_traits<
  247. Impl,
  248. typename call_traits<Impl, T, void(P0)>::result_type,
  249. void(P1, PN...)
  250. >::result_type
  251. > result_type;
  252. };
  253. struct impl
  254. {
  255. template <typename T>
  256. struct proxy
  257. {
  258. #if defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
  259. struct type
  260. {
  261. template <typename P>
  262. auto require(P&& p)
  263. noexcept(
  264. noexcept(
  265. declval<conditional_t<true, T, P>>().require(static_cast<P&&>(p))
  266. )
  267. )
  268. -> decltype(
  269. declval<conditional_t<true, T, P>>().require(static_cast<P&&>(p))
  270. );
  271. };
  272. #else // defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
  273. typedef T type;
  274. #endif // defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
  275. };
  276. template <typename T, typename Property>
  277. BOOST_ASIO_NODISCARD constexpr enable_if_t<
  278. call_traits<impl, T, void(Property)>::overload == identity,
  279. typename call_traits<impl, T, void(Property)>::result_type
  280. >
  281. operator()(T&& t, Property&&) const
  282. noexcept(call_traits<impl, T, void(Property)>::is_noexcept)
  283. {
  284. return static_cast<T&&>(t);
  285. }
  286. template <typename T, typename Property>
  287. BOOST_ASIO_NODISCARD constexpr enable_if_t<
  288. call_traits<impl, T, void(Property)>::overload == call_member,
  289. typename call_traits<impl, T, void(Property)>::result_type
  290. >
  291. operator()(T&& t, Property&& p) const
  292. noexcept(call_traits<impl, T, void(Property)>::is_noexcept)
  293. {
  294. return static_cast<T&&>(t).require(static_cast<Property&&>(p));
  295. }
  296. template <typename T, typename Property>
  297. BOOST_ASIO_NODISCARD constexpr enable_if_t<
  298. call_traits<impl, T, void(Property)>::overload == call_free,
  299. typename call_traits<impl, T, void(Property)>::result_type
  300. >
  301. operator()(T&& t, Property&& p) const
  302. noexcept(call_traits<impl, T, void(Property)>::is_noexcept)
  303. {
  304. return require(static_cast<T&&>(t), static_cast<Property&&>(p));
  305. }
  306. template <typename T, typename P0, typename P1>
  307. BOOST_ASIO_NODISCARD constexpr enable_if_t<
  308. call_traits<impl, T, void(P0, P1)>::overload == two_props,
  309. typename call_traits<impl, T, void(P0, P1)>::result_type
  310. >
  311. operator()(T&& t, P0&& p0, P1&& p1) const
  312. noexcept(call_traits<impl, T, void(P0, P1)>::is_noexcept)
  313. {
  314. return (*this)(
  315. (*this)(static_cast<T&&>(t), static_cast<P0&&>(p0)),
  316. static_cast<P1&&>(p1));
  317. }
  318. template <typename T, typename P0, typename P1,
  319. typename... PN>
  320. BOOST_ASIO_NODISCARD constexpr enable_if_t<
  321. call_traits<impl, T, void(P0, P1, PN...)>::overload == n_props,
  322. typename call_traits<impl, T, void(P0, P1, PN...)>::result_type
  323. >
  324. operator()(T&& t, P0&& p0, P1&& p1, PN&&... pn) const
  325. noexcept(call_traits<impl, T, void(P0, P1, PN...)>::is_noexcept)
  326. {
  327. return (*this)(
  328. (*this)(static_cast<T&&>(t), static_cast<P0&&>(p0)),
  329. static_cast<P1&&>(p1), static_cast<PN&&>(pn)...);
  330. }
  331. };
  332. template <typename T = impl>
  333. struct static_instance
  334. {
  335. static const T instance;
  336. };
  337. template <typename T>
  338. const T static_instance<T>::instance = {};
  339. } // namespace boost_asio_require_fn
  340. namespace boost {
  341. namespace asio {
  342. namespace {
  343. static constexpr const boost_asio_require_fn::impl&
  344. require = boost_asio_require_fn::static_instance<>::instance;
  345. } // namespace
  346. typedef boost_asio_require_fn::impl require_t;
  347. template <typename T, typename... Properties>
  348. struct can_require :
  349. integral_constant<bool,
  350. boost_asio_require_fn::call_traits<
  351. require_t, T, void(Properties...)>::overload
  352. != boost_asio_require_fn::ill_formed>
  353. {
  354. };
  355. #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
  356. template <typename T, typename... Properties>
  357. constexpr bool can_require_v
  358. = can_require<T, Properties...>::value;
  359. #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
  360. template <typename T, typename... Properties>
  361. struct is_nothrow_require :
  362. integral_constant<bool,
  363. boost_asio_require_fn::call_traits<
  364. require_t, T, void(Properties...)>::is_noexcept>
  365. {
  366. };
  367. #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
  368. template <typename T, typename... Properties>
  369. constexpr bool is_nothrow_require_v
  370. = is_nothrow_require<T, Properties...>::value;
  371. #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
  372. template <typename T, typename... Properties>
  373. struct require_result
  374. {
  375. typedef typename boost_asio_require_fn::call_traits<
  376. require_t, T, void(Properties...)>::result_type type;
  377. };
  378. template <typename T, typename... Properties>
  379. using require_result_t = typename require_result<T, Properties...>::type;
  380. } // namespace asio
  381. } // namespace boost
  382. #endif // defined(GENERATING_DOCUMENTATION)
  383. #include <boost/asio/detail/pop_options.hpp>
  384. #endif // BOOST_ASIO_REQUIRE_HPP