prefer.hpp 16 KB

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