deferred.hpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  1. //
  2. // experimental/deferred.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 BOOST_ASIO_EXPERIMENTAL_DEFERRED_HPP
  11. #define BOOST_ASIO_EXPERIMENTAL_DEFERRED_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 <tuple>
  17. #include <boost/asio/associator.hpp>
  18. #include <boost/asio/async_result.hpp>
  19. #include <boost/asio/detail/type_traits.hpp>
  20. #include <boost/asio/detail/push_options.hpp>
  21. namespace boost {
  22. namespace asio {
  23. namespace experimental {
  24. /// Trait for detecting objects that are usable as deferred operations.
  25. template <typename T>
  26. struct is_deferred : false_type
  27. {
  28. };
  29. namespace detail {
  30. // Helper trait for getting the completion signature from an async operation.
  31. struct deferred_signature_probe {};
  32. template <typename T>
  33. struct deferred_signature_probe_result
  34. {
  35. typedef T type;
  36. };
  37. template <typename T>
  38. struct deferred_signature
  39. {
  40. typedef typename decltype(
  41. declval<T>()(declval<deferred_signature_probe>()))::type type;
  42. };
  43. // Helper trait for getting the completion signature of the tail in a sequence
  44. // when invoked with the specified arguments.
  45. template <typename HeadSignature, typename Tail>
  46. struct deferred_sequence_signature;
  47. template <typename R, typename... Args, typename Tail>
  48. struct deferred_sequence_signature<R(Args...), Tail>
  49. {
  50. static_assert(
  51. !is_same<decltype(declval<Tail>()(declval<Args>()...)), void>::value,
  52. "deferred functions must produce a deferred return type");
  53. typedef typename decltype(
  54. declval<Tail>()(declval<Args>()...)(
  55. declval<deferred_signature_probe>()))::type type;
  56. };
  57. // Completion handler for the head component of a deferred sequence.
  58. template <typename Handler, typename Tail>
  59. class deferred_sequence_handler
  60. {
  61. public:
  62. template <typename H, typename T>
  63. explicit deferred_sequence_handler(
  64. BOOST_ASIO_MOVE_ARG(H) handler, BOOST_ASIO_MOVE_ARG(T) tail)
  65. : handler_(BOOST_ASIO_MOVE_CAST(H)(handler)),
  66. tail_(BOOST_ASIO_MOVE_CAST(T)(tail))
  67. {
  68. }
  69. template <typename... Args>
  70. void operator()(BOOST_ASIO_MOVE_ARG(Args)... args)
  71. {
  72. BOOST_ASIO_MOVE_OR_LVALUE(Tail)(tail_)(
  73. BOOST_ASIO_MOVE_CAST(Args)(args)...)(
  74. BOOST_ASIO_MOVE_OR_LVALUE(Handler)(handler_));
  75. }
  76. //private:
  77. Handler handler_;
  78. Tail tail_;
  79. };
  80. } // namespace detail
  81. /// Used to represent an empty deferred action.
  82. struct deferred_noop
  83. {
  84. /// No effect.
  85. template <typename... Args>
  86. void operator()(BOOST_ASIO_MOVE_ARG(Args)...) BOOST_ASIO_RVALUE_REF_QUAL
  87. {
  88. }
  89. #if defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS)
  90. /// No effect.
  91. template <typename... Args>
  92. decltype(auto) operator()(BOOST_ASIO_MOVE_ARG(Args)...) const &
  93. {
  94. }
  95. #endif // defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS)
  96. };
  97. #if !defined(GENERATING_DOCUMENTATION)
  98. template <>
  99. struct is_deferred<deferred_noop> : true_type
  100. {
  101. };
  102. #endif // !defined(GENERATING_DOCUMENTATION)
  103. /// Tag type to disambiguate deferred constructors.
  104. struct deferred_init_tag {};
  105. /// Wraps a function object so that it may be used as an element in a deferred
  106. /// composition.
  107. template <typename Function>
  108. class deferred_function
  109. {
  110. public:
  111. /// Constructor.
  112. template <typename F>
  113. BOOST_ASIO_CONSTEXPR explicit deferred_function(
  114. deferred_init_tag, BOOST_ASIO_MOVE_ARG(F) function)
  115. : function_(BOOST_ASIO_MOVE_CAST(F)(function))
  116. {
  117. }
  118. template <typename... Args>
  119. decltype(auto) operator()(
  120. BOOST_ASIO_MOVE_ARG(Args)... args) BOOST_ASIO_RVALUE_REF_QUAL
  121. {
  122. return BOOST_ASIO_MOVE_CAST(Function)(function_)(
  123. BOOST_ASIO_MOVE_CAST(Args)(args)...);
  124. }
  125. #if defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS)
  126. template <typename... Args>
  127. decltype(auto) operator()(
  128. BOOST_ASIO_MOVE_ARG(Args)... args) const &
  129. {
  130. return deferred_function(*this)(
  131. BOOST_ASIO_MOVE_CAST(Args)(args)...);
  132. }
  133. #endif // defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS)
  134. //private:
  135. Function function_;
  136. };
  137. #if !defined(GENERATING_DOCUMENTATION)
  138. template <typename Function>
  139. struct is_deferred<deferred_function<Function> > : true_type
  140. {
  141. };
  142. #endif // !defined(GENERATING_DOCUMENTATION)
  143. /// Encapsulates deferred values.
  144. template <typename... Values>
  145. class BOOST_ASIO_NODISCARD deferred_values
  146. {
  147. private:
  148. std::tuple<Values...> values_;
  149. struct initiate
  150. {
  151. template <typename Handler, typename... V>
  152. void operator()(Handler handler, BOOST_ASIO_MOVE_ARG(V)... values)
  153. {
  154. BOOST_ASIO_MOVE_OR_LVALUE(Handler)(handler)(
  155. BOOST_ASIO_MOVE_CAST(V)(values)...);
  156. }
  157. };
  158. template <typename CompletionToken, std::size_t... I>
  159. decltype(auto) invoke_helper(
  160. BOOST_ASIO_MOVE_ARG(CompletionToken) token,
  161. std::index_sequence<I...>)
  162. {
  163. return boost::asio::async_initiate<CompletionToken, void(Values...)>(
  164. initiate(), token,
  165. std::get<I>(BOOST_ASIO_MOVE_CAST(std::tuple<Values...>)(values_))...);
  166. }
  167. public:
  168. /// Construct a deferred asynchronous operation from the arguments to an
  169. /// initiation function object.
  170. template <typename... V>
  171. BOOST_ASIO_CONSTEXPR explicit deferred_values(
  172. deferred_init_tag, BOOST_ASIO_MOVE_ARG(V)... values)
  173. : values_(BOOST_ASIO_MOVE_CAST(V)(values)...)
  174. {
  175. }
  176. /// Initiate the deferred operation using the supplied completion token.
  177. template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(Values...)) CompletionToken>
  178. decltype(auto) operator()(
  179. BOOST_ASIO_MOVE_ARG(CompletionToken) token) BOOST_ASIO_RVALUE_REF_QUAL
  180. {
  181. return this->invoke_helper(
  182. BOOST_ASIO_MOVE_CAST(CompletionToken)(token),
  183. std::index_sequence_for<Values...>());
  184. }
  185. #if defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS)
  186. template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(Values...)) CompletionToken>
  187. decltype(auto) operator()(
  188. BOOST_ASIO_MOVE_ARG(CompletionToken) token) const &
  189. {
  190. return deferred_values(*this)(
  191. BOOST_ASIO_MOVE_CAST(CompletionToken)(token));
  192. }
  193. #endif // defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS)
  194. };
  195. #if !defined(GENERATING_DOCUMENTATION)
  196. template <typename... Values>
  197. struct is_deferred<deferred_values<Values...> > : true_type
  198. {
  199. };
  200. #endif // !defined(GENERATING_DOCUMENTATION)
  201. /// Encapsulates a deferred asynchronous operation.
  202. template <typename Signature, typename Initiation, typename... InitArgs>
  203. class BOOST_ASIO_NODISCARD deferred_async_operation
  204. {
  205. private:
  206. typename decay<Initiation>::type initiation_;
  207. typedef std::tuple<typename decay<InitArgs>::type...> init_args_t;
  208. init_args_t init_args_;
  209. template <typename CompletionToken, std::size_t... I>
  210. decltype(auto) invoke_helper(
  211. BOOST_ASIO_MOVE_ARG(CompletionToken) token,
  212. std::index_sequence<I...>)
  213. {
  214. return boost::asio::async_initiate<CompletionToken, Signature>(
  215. BOOST_ASIO_MOVE_CAST(typename decay<Initiation>::type)(initiation_),
  216. token, std::get<I>(BOOST_ASIO_MOVE_CAST(init_args_t)(init_args_))...);
  217. }
  218. public:
  219. /// Construct a deferred asynchronous operation from the arguments to an
  220. /// initiation function object.
  221. template <typename I, typename... A>
  222. BOOST_ASIO_CONSTEXPR explicit deferred_async_operation(
  223. deferred_init_tag, BOOST_ASIO_MOVE_ARG(I) initiation,
  224. BOOST_ASIO_MOVE_ARG(A)... init_args)
  225. : initiation_(BOOST_ASIO_MOVE_CAST(I)(initiation)),
  226. init_args_(BOOST_ASIO_MOVE_CAST(A)(init_args)...)
  227. {
  228. }
  229. /// Initiate the asynchronous operation using the supplied completion token.
  230. template <BOOST_ASIO_COMPLETION_TOKEN_FOR(Signature) CompletionToken>
  231. decltype(auto) operator()(
  232. BOOST_ASIO_MOVE_ARG(CompletionToken) token) BOOST_ASIO_RVALUE_REF_QUAL
  233. {
  234. return this->invoke_helper(
  235. BOOST_ASIO_MOVE_CAST(CompletionToken)(token),
  236. std::index_sequence_for<InitArgs...>());
  237. }
  238. #if defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS)
  239. template <BOOST_ASIO_COMPLETION_TOKEN_FOR(Signature) CompletionToken>
  240. decltype(auto) operator()(
  241. BOOST_ASIO_MOVE_ARG(CompletionToken) token) const &
  242. {
  243. return deferred_async_operation(*this)(
  244. BOOST_ASIO_MOVE_CAST(CompletionToken)(token));
  245. }
  246. #endif // defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS)
  247. };
  248. #if !defined(GENERATING_DOCUMENTATION)
  249. template <typename Signature, typename Initiation, typename... InitArgs>
  250. struct is_deferred<
  251. deferred_async_operation<Signature, Initiation, InitArgs...> > : true_type
  252. {
  253. };
  254. #endif // !defined(GENERATING_DOCUMENTATION)
  255. /// Defines a link between two consecutive operations in a sequence.
  256. template <typename Head, typename Tail>
  257. class BOOST_ASIO_NODISCARD deferred_sequence
  258. {
  259. private:
  260. typedef typename detail::deferred_sequence_signature<
  261. typename detail::deferred_signature<Head>::type, Tail>::type
  262. signature;
  263. public:
  264. template <typename H, typename T>
  265. BOOST_ASIO_CONSTEXPR explicit deferred_sequence(deferred_init_tag,
  266. BOOST_ASIO_MOVE_ARG(H) head, BOOST_ASIO_MOVE_ARG(T) tail)
  267. : head_(BOOST_ASIO_MOVE_CAST(H)(head)),
  268. tail_(BOOST_ASIO_MOVE_CAST(T)(tail))
  269. {
  270. }
  271. template <BOOST_ASIO_COMPLETION_TOKEN_FOR(signature) CompletionToken>
  272. decltype(auto) operator()(
  273. BOOST_ASIO_MOVE_ARG(CompletionToken) token) BOOST_ASIO_RVALUE_REF_QUAL
  274. {
  275. return boost::asio::async_initiate<CompletionToken, signature>(
  276. initiate(), token, BOOST_ASIO_MOVE_OR_LVALUE(Head)(head_),
  277. BOOST_ASIO_MOVE_OR_LVALUE(Tail)(tail_));
  278. }
  279. #if defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS)
  280. template <BOOST_ASIO_COMPLETION_TOKEN_FOR(signature) CompletionToken>
  281. decltype(auto) operator()(
  282. BOOST_ASIO_MOVE_ARG(CompletionToken) token) const &
  283. {
  284. return deferred_sequence(*this)(
  285. BOOST_ASIO_MOVE_CAST(CompletionToken)(token));
  286. }
  287. #endif // defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS)
  288. private:
  289. struct initiate
  290. {
  291. template <typename Handler>
  292. void operator()(BOOST_ASIO_MOVE_ARG(Handler) handler,
  293. Head head, BOOST_ASIO_MOVE_ARG(Tail) tail)
  294. {
  295. BOOST_ASIO_MOVE_OR_LVALUE(Head)(head)(
  296. detail::deferred_sequence_handler<
  297. typename decay<Handler>::type,
  298. typename decay<Tail>::type>(
  299. BOOST_ASIO_MOVE_CAST(Handler)(handler),
  300. BOOST_ASIO_MOVE_CAST(Tail)(tail)));
  301. }
  302. };
  303. Head head_;
  304. Tail tail_;
  305. };
  306. #if !defined(GENERATING_DOCUMENTATION)
  307. template <typename Head, typename Tail>
  308. struct is_deferred<deferred_sequence<Head, Tail> > : true_type
  309. {
  310. };
  311. #endif // !defined(GENERATING_DOCUMENTATION)
  312. /// Used to represent a deferred conditional branch.
  313. template <typename OnTrue = deferred_noop,
  314. typename OnFalse = deferred_noop>
  315. class BOOST_ASIO_NODISCARD deferred_conditional
  316. {
  317. public:
  318. /// Construct a deferred conditional with the value to determine which branch
  319. /// will be executed.
  320. BOOST_ASIO_CONSTEXPR explicit deferred_conditional(bool b)
  321. : on_true_(),
  322. on_false_(),
  323. bool_(b)
  324. {
  325. }
  326. /// Invoke the conditional branch bsaed on the stored alue.
  327. template <typename... Args>
  328. auto operator()(BOOST_ASIO_MOVE_ARG(Args)... args) BOOST_ASIO_RVALUE_REF_QUAL
  329. {
  330. if (bool_)
  331. {
  332. return BOOST_ASIO_MOVE_OR_LVALUE(OnTrue)(on_true_)(
  333. BOOST_ASIO_MOVE_CAST(Args)(args)...);
  334. }
  335. else
  336. {
  337. return BOOST_ASIO_MOVE_OR_LVALUE(OnFalse)(on_false_)(
  338. BOOST_ASIO_MOVE_CAST(Args)(args)...);
  339. }
  340. }
  341. #if defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS)
  342. template <typename... Args>
  343. auto operator()(BOOST_ASIO_MOVE_ARG(Args)... args) const &
  344. {
  345. return deferred_conditional(*this)(
  346. BOOST_ASIO_MOVE_CAST(Args)(args)...);
  347. }
  348. #endif // defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS)
  349. /// Set the true branch of the conditional.
  350. template <typename T>
  351. deferred_conditional<T, OnFalse> then(T on_true,
  352. typename constraint<
  353. is_deferred<T>::value
  354. >::type* = 0,
  355. typename constraint<
  356. is_same<
  357. typename conditional<true, OnTrue, T>::type,
  358. deferred_noop
  359. >::value
  360. >::type* = 0) BOOST_ASIO_RVALUE_REF_QUAL
  361. {
  362. return deferred_conditional<T, OnFalse>(
  363. bool_, BOOST_ASIO_MOVE_CAST(T)(on_true),
  364. BOOST_ASIO_MOVE_CAST(OnFalse)(on_false_));
  365. }
  366. /// Set the false branch of the conditional.
  367. template <typename T>
  368. deferred_conditional<OnTrue, T> otherwise(T on_false,
  369. typename constraint<
  370. is_deferred<T>::value
  371. >::type* = 0,
  372. typename constraint<
  373. !is_same<
  374. typename conditional<true, OnTrue, T>::type,
  375. deferred_noop
  376. >::value
  377. >::type* = 0,
  378. typename constraint<
  379. is_same<
  380. typename conditional<true, OnFalse, T>::type,
  381. deferred_noop
  382. >::value
  383. >::type* = 0) BOOST_ASIO_RVALUE_REF_QUAL
  384. {
  385. return deferred_conditional<OnTrue, T>(
  386. bool_, BOOST_ASIO_MOVE_CAST(OnTrue)(on_true_),
  387. BOOST_ASIO_MOVE_CAST(T)(on_false));
  388. }
  389. private:
  390. template <typename T, typename F> friend class deferred_conditional;
  391. // Helper constructor.
  392. template <typename T, typename F>
  393. explicit deferred_conditional(bool b, BOOST_ASIO_MOVE_ARG(T) on_true,
  394. BOOST_ASIO_MOVE_ARG(F) on_false)
  395. : on_true_(BOOST_ASIO_MOVE_CAST(T)(on_true)),
  396. on_false_(BOOST_ASIO_MOVE_CAST(F)(on_false)),
  397. bool_(b)
  398. {
  399. }
  400. OnTrue on_true_;
  401. OnFalse on_false_;
  402. bool bool_;
  403. };
  404. #if !defined(GENERATING_DOCUMENTATION)
  405. template <typename OnTrue, typename OnFalse>
  406. struct is_deferred<deferred_conditional<OnTrue, OnFalse> > : true_type
  407. {
  408. };
  409. #endif // !defined(GENERATING_DOCUMENTATION)
  410. /// Class used to specify that an asynchronous operation should return a
  411. /// function object to lazily launch the operation.
  412. /**
  413. * The deferred_t class is used to indicate that an asynchronous operation
  414. * should return a function object which is itself an initiation function. A
  415. * deferred_t object may be passed as a completion token to an asynchronous
  416. * operation, typically using the special value @c boost::asio::deferred. For
  417. * example:
  418. *
  419. * @code auto my_sender
  420. * = my_socket.async_read_some(my_buffer,
  421. * boost::asio::experimental::deferred); @endcode
  422. *
  423. * The initiating function (async_read_some in the above example) returns a
  424. * function object that will lazily initiate the operation.
  425. */
  426. class deferred_t
  427. {
  428. public:
  429. /// Default constructor.
  430. BOOST_ASIO_CONSTEXPR deferred_t()
  431. {
  432. }
  433. /// Adapts an executor to add the @c deferred_t completion token as the
  434. /// default.
  435. template <typename InnerExecutor>
  436. struct executor_with_default : InnerExecutor
  437. {
  438. /// Specify @c deferred_t as the default completion token type.
  439. typedef deferred_t default_completion_token_type;
  440. /// Construct the adapted executor from the inner executor type.
  441. template <typename InnerExecutor1>
  442. executor_with_default(const InnerExecutor1& ex,
  443. typename constraint<
  444. conditional<
  445. !is_same<InnerExecutor1, executor_with_default>::value,
  446. is_convertible<InnerExecutor1, InnerExecutor>,
  447. false_type
  448. >::type::value
  449. >::type = 0) BOOST_ASIO_NOEXCEPT
  450. : InnerExecutor(ex)
  451. {
  452. }
  453. };
  454. /// Type alias to adapt an I/O object to use @c deferred_t as its
  455. /// default completion token type.
  456. #if defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) \
  457. || defined(GENERATING_DOCUMENTATION)
  458. template <typename T>
  459. using as_default_on_t = typename T::template rebind_executor<
  460. executor_with_default<typename T::executor_type> >::other;
  461. #endif // defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES)
  462. // || defined(GENERATING_DOCUMENTATION)
  463. /// Function helper to adapt an I/O object to use @c deferred_t as its
  464. /// default completion token type.
  465. template <typename T>
  466. static typename decay<T>::type::template rebind_executor<
  467. executor_with_default<typename decay<T>::type::executor_type>
  468. >::other
  469. as_default_on(BOOST_ASIO_MOVE_ARG(T) object)
  470. {
  471. return typename decay<T>::type::template rebind_executor<
  472. executor_with_default<typename decay<T>::type::executor_type>
  473. >::other(BOOST_ASIO_MOVE_CAST(T)(object));
  474. }
  475. /// Creates a new deferred from a function.
  476. template <typename Function>
  477. typename constraint<
  478. !is_deferred<typename decay<Function>::type>::value,
  479. deferred_function<typename decay<Function>::type>
  480. >::type operator()(BOOST_ASIO_MOVE_ARG(Function) function) const
  481. {
  482. return deferred_function<typename decay<Function>::type>(
  483. deferred_init_tag{}, BOOST_ASIO_MOVE_CAST(Function)(function));
  484. }
  485. /// Passes through anything that is already deferred.
  486. template <typename T>
  487. typename constraint<
  488. is_deferred<typename decay<T>::type>::value,
  489. typename decay<T>::type
  490. >::type operator()(BOOST_ASIO_MOVE_ARG(T) t) const
  491. {
  492. return BOOST_ASIO_MOVE_CAST(T)(t);
  493. }
  494. /// Returns a deferred operation that returns the provided values.
  495. template <typename... Args>
  496. static BOOST_ASIO_CONSTEXPR deferred_values<typename decay<Args>::type...>
  497. values(BOOST_ASIO_MOVE_ARG(Args)... args)
  498. {
  499. return deferred_values<typename decay<Args>::type...>(
  500. deferred_init_tag{}, BOOST_ASIO_MOVE_CAST(Args)(args)...);
  501. }
  502. /// Creates a conditional object for branching deferred operations.
  503. static BOOST_ASIO_CONSTEXPR deferred_conditional<> when(bool b)
  504. {
  505. return deferred_conditional<>(b);
  506. }
  507. };
  508. /// Pipe operator used to chain deferred operations.
  509. template <typename Head, typename Tail>
  510. inline auto operator|(Head head, BOOST_ASIO_MOVE_ARG(Tail) tail)
  511. -> typename constraint<
  512. is_deferred<Head>::value,
  513. decltype(BOOST_ASIO_MOVE_OR_LVALUE(Head)(head)(
  514. BOOST_ASIO_MOVE_CAST(Tail)(tail)))
  515. >::type
  516. {
  517. return BOOST_ASIO_MOVE_OR_LVALUE(Head)(head)(
  518. BOOST_ASIO_MOVE_CAST(Tail)(tail));
  519. }
  520. /// A special value, similar to std::nothrow.
  521. /**
  522. * See the documentation for boost::asio::experimental::deferred_t for a usage
  523. * example.
  524. */
  525. #if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
  526. constexpr deferred_t deferred;
  527. #elif defined(BOOST_ASIO_MSVC)
  528. __declspec(selectany) deferred_t deferred;
  529. #endif
  530. } // namespace experimental
  531. } // namespace asio
  532. } // namespace boost
  533. #include <boost/asio/detail/pop_options.hpp>
  534. #include <boost/asio/experimental/impl/deferred.hpp>
  535. #endif // BOOST_ASIO_EXPERIMENTAL_DEFERRED_HPP