post.hpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. //
  2. // post.hpp
  3. // ~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2025 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_POST_HPP
  11. #define BOOST_ASIO_POST_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/async_result.hpp>
  17. #include <boost/asio/detail/initiate_post.hpp>
  18. #include <boost/asio/detail/type_traits.hpp>
  19. #include <boost/asio/execution_context.hpp>
  20. #include <boost/asio/execution/blocking.hpp>
  21. #include <boost/asio/execution/executor.hpp>
  22. #include <boost/asio/is_executor.hpp>
  23. #include <boost/asio/require.hpp>
  24. #include <boost/asio/detail/push_options.hpp>
  25. namespace boost {
  26. namespace asio {
  27. /// Submits a completion token or function object for execution.
  28. /**
  29. * This function submits an object for execution using the object's associated
  30. * executor. The function object is queued for execution, and is never called
  31. * from the current thread prior to returning from <tt>post()</tt>.
  32. *
  33. * The use of @c post(), rather than @ref defer(), indicates the caller's
  34. * preference that the function object be eagerly queued for execution.
  35. *
  36. * @param token The @ref completion_token that will be used to produce a
  37. * completion handler. The function signature of the completion handler must be:
  38. * @code void handler(); @endcode
  39. *
  40. * @returns This function returns <tt>async_initiate<NullaryToken,
  41. * void()>(Init{}, token)</tt>, where @c Init is a function object type defined
  42. * as:
  43. *
  44. * @code class Init
  45. * {
  46. * public:
  47. * template <typename CompletionHandler>
  48. * void operator()(CompletionHandler&& completion_handler) const;
  49. * }; @endcode
  50. *
  51. * The function call operator of @c Init:
  52. *
  53. * @li Obtains the handler's associated executor object @c ex of type @c Ex by
  54. * performing
  55. * @code auto ex = get_associated_executor(completion_handler); @endcode
  56. *
  57. * @li Obtains the handler's associated allocator object @c alloc by performing
  58. * @code auto alloc = get_associated_allocator(completion_handler); @endcode
  59. *
  60. * @li If <tt>execution::is_executor<Ex>::value</tt> is true, performs
  61. * @code prefer(
  62. * require(ex, execution::blocking.never),
  63. * execution::relationship.fork,
  64. * execution::allocator(alloc)
  65. * ).execute(std::forward<CompletionHandler>(completion_handler)); @endcode
  66. *
  67. * @li If <tt>execution::is_executor<Ex>::value</tt> is false, performs
  68. * @code ex.post(
  69. * std::forward<CompletionHandler>(completion_handler),
  70. * alloc); @endcode
  71. *
  72. * @par Completion Signature
  73. * @code void() @endcode
  74. */
  75. template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) NullaryToken = deferred_t>
  76. inline auto post(NullaryToken&& token = deferred_t())
  77. -> decltype(
  78. async_initiate<NullaryToken, void()>(
  79. declval<detail::initiate_post>(), token))
  80. {
  81. return async_initiate<NullaryToken, void()>(
  82. detail::initiate_post(), token);
  83. }
  84. /// Submits a completion token or function object for execution.
  85. /**
  86. * This function submits an object for execution using the specified executor.
  87. * The function object is queued for execution, and is never called from the
  88. * current thread prior to returning from <tt>post()</tt>.
  89. *
  90. * The use of @c post(), rather than @ref defer(), indicates the caller's
  91. * preference that the function object be eagerly queued for execution.
  92. *
  93. * @param ex The target executor.
  94. *
  95. * @param token The @ref completion_token that will be used to produce a
  96. * completion handler. The function signature of the completion handler must be:
  97. * @code void handler(); @endcode
  98. *
  99. * @returns This function returns <tt>async_initiate<NullaryToken,
  100. * void()>(Init{ex}, token)</tt>, where @c Init is a function object type
  101. * defined as:
  102. *
  103. * @code class Init
  104. * {
  105. * public:
  106. * using executor_type = Executor;
  107. * explicit Init(const Executor& ex) : ex_(ex) {}
  108. * executor_type get_executor() const noexcept { return ex_; }
  109. * template <typename CompletionHandler>
  110. * void operator()(CompletionHandler&& completion_handler) const;
  111. * private:
  112. * Executor ex_; // exposition only
  113. * }; @endcode
  114. *
  115. * The function call operator of @c Init:
  116. *
  117. * @li Obtains the handler's associated executor object @c ex1 of type @c Ex1 by
  118. * performing
  119. * @code auto ex1 = get_associated_executor(completion_handler, ex); @endcode
  120. *
  121. * @li Obtains the handler's associated allocator object @c alloc by performing
  122. * @code auto alloc = get_associated_allocator(completion_handler); @endcode
  123. *
  124. * @li If <tt>execution::is_executor<Ex1>::value</tt> is true, constructs a
  125. * function object @c f with a member @c executor_ that is initialised with
  126. * <tt>prefer(ex1, execution::outstanding_work.tracked)</tt>, a member @c
  127. * handler_ that is a decay-copy of @c completion_handler, and a function call
  128. * operator that performs:
  129. * @code auto a = get_associated_allocator(handler_);
  130. * prefer(executor_, execution::allocator(a)).execute(std::move(handler_));
  131. * @endcode
  132. *
  133. * @li If <tt>execution::is_executor<Ex1>::value</tt> is false, constructs a
  134. * function object @c f with a member @c work_ that is initialised with
  135. * <tt>make_work_guard(ex1)</tt>, a member @c handler_ that is a decay-copy of
  136. * @c completion_handler, and a function call operator that performs:
  137. * @code auto a = get_associated_allocator(handler_);
  138. * work_.get_executor().dispatch(std::move(handler_), a);
  139. * work_.reset(); @endcode
  140. *
  141. * @li If <tt>execution::is_executor<Executor>::value</tt> is true, performs
  142. * @code prefer(
  143. * require(ex, execution::blocking.never),
  144. * execution::relationship.fork,
  145. * execution::allocator(alloc)
  146. * ).execute(std::move(f)); @endcode
  147. *
  148. * @li If <tt>execution::is_executor<Executor>::value</tt> is false, performs
  149. * @code ex.post(std::move(f), alloc); @endcode
  150. *
  151. * @par Completion Signature
  152. * @code void() @endcode
  153. */
  154. template <typename Executor,
  155. BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) NullaryToken
  156. = default_completion_token_t<Executor>>
  157. inline auto post(const Executor& ex,
  158. NullaryToken&& token = default_completion_token_t<Executor>(),
  159. constraint_t<
  160. (execution::is_executor<Executor>::value
  161. && can_require<Executor, execution::blocking_t::never_t>::value)
  162. || is_executor<Executor>::value
  163. > = 0)
  164. -> decltype(
  165. async_initiate<NullaryToken, void()>(
  166. declval<detail::initiate_post_with_executor<Executor>>(),
  167. token, detail::empty_work_function()))
  168. {
  169. return async_initiate<NullaryToken, void()>(
  170. detail::initiate_post_with_executor<Executor>(ex),
  171. token, detail::empty_work_function());
  172. }
  173. /// Submits a completion token or function object for execution.
  174. /**
  175. * @param ctx An execution context, from which the target executor is obtained.
  176. *
  177. * @param token The @ref completion_token that will be used to produce a
  178. * completion handler. The function signature of the completion handler must be:
  179. * @code void handler(); @endcode
  180. *
  181. * @returns <tt>post(ctx.get_executor(), forward<NullaryToken>(token))</tt>.
  182. *
  183. * @par Completion Signature
  184. * @code void() @endcode
  185. */
  186. template <typename ExecutionContext,
  187. BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) NullaryToken
  188. = default_completion_token_t<typename ExecutionContext::executor_type>>
  189. inline auto post(ExecutionContext& ctx,
  190. NullaryToken&& token = default_completion_token_t<
  191. typename ExecutionContext::executor_type>(),
  192. constraint_t<
  193. is_convertible<ExecutionContext&, execution_context&>::value
  194. > = 0)
  195. -> decltype(
  196. async_initiate<NullaryToken, void()>(
  197. declval<detail::initiate_post_with_executor<
  198. typename ExecutionContext::executor_type>>(),
  199. token, detail::empty_work_function()))
  200. {
  201. return async_initiate<NullaryToken, void()>(
  202. detail::initiate_post_with_executor<
  203. typename ExecutionContext::executor_type>(ctx.get_executor()),
  204. token, detail::empty_work_function());
  205. }
  206. /// Submits a function to be run on a specified target executor, and after
  207. /// completion submits the completion handler.
  208. /**
  209. * This function submits a function object for execution on the specified
  210. * executor. The function object is queued for execution, and is never called
  211. * from the current thread prior to returning from <tt>post()</tt>. After the
  212. * submitted function completes, the completion handler is dispatched to run on
  213. * its associated executor.
  214. *
  215. * The use of @c post(), rather than @ref defer(), indicates the caller's
  216. * preference that the function object be eagerly queued for execution.
  217. *
  218. * @param function A nullary function to be executed on the target executor.
  219. *
  220. * @param ex The target executor.
  221. *
  222. * @param token The @ref completion_token that will be used to produce a
  223. * completion handler. The function signature of the completion handler must be:
  224. * @code void handler(); @endcode
  225. *
  226. * @returns This function returns <tt>async_initiate<NullaryToken,
  227. * void()>(Init{ex}, token, forward<Function>(function))</tt>, where @c Init is
  228. * a function object type defined as:
  229. *
  230. * @code class Init
  231. * {
  232. * public:
  233. * using executor_type = Executor;
  234. * explicit Init(const Executor& ex) : ex_(ex) {}
  235. * executor_type get_executor() const noexcept { return ex_; }
  236. * template <typename CompletionHandler>
  237. * void operator()(CompletionHandler&& completion_handler,
  238. * Function&& function) const;
  239. * private:
  240. * Executor ex_; // exposition only
  241. * }; @endcode
  242. *
  243. * The function call operator of @c Init:
  244. *
  245. * @li Obtains the handler's associated executor object @c ex1 of type @c Ex1 by
  246. * performing
  247. * @code auto ex1 = get_associated_executor(completion_handler, ex); @endcode
  248. *
  249. * @li Obtains the handler's associated allocator object @c alloc by performing
  250. * @code auto alloc = get_associated_allocator(completion_handler); @endcode
  251. *
  252. * @li If <tt>execution::is_executor<Ex1>::value</tt> is true, constructs a
  253. * function object wrapper @c f with a member @c executor_ that is initialised
  254. * with <tt>prefer(ex1, execution::outstanding_work.tracked)</tt>, a member @c
  255. * function_ that is a decay-copy of @c function, a member @c handler_ that is a
  256. * decay-copy of @c completion_handler, and a function call operator that
  257. * performs:
  258. * @code std::move(function_)();
  259. * auto a = get_associated_allocator(handler_);
  260. * prefer(executor_, execution::allocator(a)).execute(std::move(handler_));
  261. * @endcode
  262. *
  263. * @li If <tt>execution::is_executor<Ex1>::value</tt> is false, constructs a
  264. * function object wrapper @c f with a member @c work_ that is initialised with
  265. * <tt>make_work_guard(ex1)</tt>, a member @c function_ that is a decay-copy of
  266. * @c function, a member @c handler_ that is a decay-copy of @c
  267. * completion_handler, and a function call operator that performs:
  268. * @code std::move(function_)();
  269. * auto a = get_associated_allocator(handler_);
  270. * work_.get_executor().dispatch(std::move(handler_), a);
  271. * work_.reset(); @endcode
  272. *
  273. * @li If <tt>execution::is_executor<Executor>::value</tt> is true, performs
  274. * @code prefer(
  275. * require(ex, execution::blocking.never),
  276. * execution::relationship.fork,
  277. * execution::allocator(alloc)
  278. * ).execute(std::move(f)); @endcode
  279. *
  280. * @li If <tt>execution::is_executor<Executor>::value</tt> is false, performs
  281. * @code ex.post(std::move(f), alloc); @endcode
  282. *
  283. * @note If the function object throws an exception, that exception is allowed
  284. * to propagate to the target executor. The behaviour in this case is dependent
  285. * on the executor. For example, boost::asio::io_context will allow the
  286. * exception to propagate to the caller that runs the @c io_context, whereas
  287. * boost::asio::thread_pool will call @c std::terminate.
  288. *
  289. * @par Example
  290. * This @c post overload may be used to submit long running work to a thread
  291. * pool and, once complete, continue execution on an associated completion
  292. * executor, such as a coroutine's associated executor:
  293. * @code boost::asio::awaitable<void> my_coroutine()
  294. * {
  295. * // ...
  296. *
  297. * co_await boost::asio::post(
  298. * []{
  299. * perform_expensive_computation();
  300. * },
  301. * my_thread_pool);
  302. *
  303. * // handle result on the coroutine's associated executor
  304. * } @endcode
  305. *
  306. * @par Completion Signature
  307. * @code void() @endcode
  308. */
  309. template <typename Function, typename Executor,
  310. BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) NullaryToken
  311. = default_completion_token_t<Executor>>
  312. inline auto post(Function&& function, const Executor& ex,
  313. NullaryToken&& token = default_completion_token_t<Executor>(),
  314. constraint_t<
  315. is_void<result_of_t<decay_t<Function>()>>::value
  316. > = 0,
  317. constraint_t<
  318. (execution::is_executor<Executor>::value
  319. && can_require<Executor, execution::blocking_t::never_t>::value)
  320. || is_executor<Executor>::value
  321. > = 0)
  322. -> decltype(
  323. async_initiate<NullaryToken, void()>(
  324. declval<detail::initiate_post_with_executor<Executor>>(),
  325. token, static_cast<Function&&>(function)))
  326. {
  327. return async_initiate<NullaryToken, void()>(
  328. detail::initiate_post_with_executor<Executor>(ex),
  329. token, static_cast<Function&&>(function));
  330. }
  331. /// Submits a function to be run on a specified target executor, and passes the
  332. /// result to a completion handler.
  333. /**
  334. * This function submits a function object for execution on the specified
  335. * executor. The function object is queued for execution, and is never called
  336. * from the current thread prior to returning from <tt>post()</tt>. After the
  337. * submitted function completes, the completion handler is dispatched along with
  338. * the function's result, to run on its associated executor.
  339. *
  340. * The use of @c post(), rather than @ref defer(), indicates the caller's
  341. * preference that the function object be eagerly queued for execution.
  342. *
  343. * @param function A nullary function to be executed on the target executor.
  344. *
  345. * @param ex The target executor.
  346. *
  347. * @param token The @ref completion_token that will be used to produce a
  348. * completion handler. The function signature of the completion handler must be:
  349. * @code void handler(decay_t<result_of_t<decay_t<Function>()>>); @endcode
  350. *
  351. * @returns This function returns <tt>async_initiate<CompletionToken,
  352. * void()>(Init{ex}, token)</tt>, where @c Init is a function object type
  353. * defined as:
  354. *
  355. * @code class Init
  356. * {
  357. * public:
  358. * using executor_type = Executor;
  359. * explicit Init(const Executor& ex) : ex_(ex) {}
  360. * executor_type get_executor() const noexcept { return ex_; }
  361. * template <typename CompletionHandler>
  362. * void operator()(CompletionHandler&& completion_handler,
  363. * Function&& function) const;
  364. * private:
  365. * Executor ex_; // exposition only
  366. * }; @endcode
  367. *
  368. * The function call operator of @c Init:
  369. *
  370. * @li Obtains the handler's associated executor object @c ex1 of type @c Ex1 by
  371. * performing
  372. * @code auto ex1 = get_associated_executor(completion_handler, ex); @endcode
  373. *
  374. * @li Obtains the handler's associated allocator object @c alloc by performing
  375. * @code auto alloc = get_associated_allocator(completion_handler); @endcode
  376. *
  377. * @li If <tt>execution::is_executor<Ex1>::value</tt> is true, constructs a
  378. * function object wrapper @c f with a member @c executor_ that is initialised
  379. * with <tt>prefer(ex1, execution::outstanding_work.tracked)</tt>, a member @c
  380. * function_ that is a decay-copy of @c function, a member @c handler_ that is a
  381. * decay-copy of @c completion_handler, and a function call operator that
  382. * performs:
  383. * @code auto result = std::move(function_)();
  384. * auto a = get_associated_allocator(handler_);
  385. * prefer(executor_, execution::allocator(a)).execute(
  386. * std::bind(std::move(handler_), std::move(result)));
  387. * @endcode
  388. *
  389. * @li If <tt>execution::is_executor<Ex1>::value</tt> is false, constructs a
  390. * function object wrapper @c f with a member @c work_ that is initialised with
  391. * <tt>make_work_guard(ex1)</tt>, a member @c function_ that is a decay-copy of
  392. * @c function, a member @c handler_ that is a decay-copy of @c
  393. * completion_handler, and a function call operator that performs:
  394. * @code auto result = std::move(function_)();
  395. * auto a = get_associated_allocator(handler_);
  396. * work_.get_executor().dispatch(
  397. * std::bind(std::move(handler_), std::move(result)), a);
  398. * work_.reset(); @endcode
  399. *
  400. * @li If <tt>execution::is_executor<Executor>::value</tt> is true, performs
  401. * @code prefer(
  402. * require(ex, execution::blocking.never),
  403. * execution::relationship.fork,
  404. * execution::allocator(alloc)
  405. * ).execute(std::move(f)); @endcode
  406. *
  407. * @li If <tt>execution::is_executor<Executor>::value</tt> is false, performs
  408. * @code ex.post(std::move(f), alloc); @endcode
  409. *
  410. * @note If the function object throws an exception, that exception is allowed
  411. * to propagate to the target executor. The behaviour in this case is dependent
  412. * on the executor. For example, boost::asio::io_context will allow the
  413. * exception to propagate to the caller that runs the @c io_context, whereas
  414. * boost::asio::thread_pool will call @c std::terminate.
  415. *
  416. * @par Example
  417. * This @c post overload may be used to submit long running work to a thread
  418. * pool and, once complete, continue execution on an associated completion
  419. * executor, such as a coroutine's associated executor:
  420. * @code boost::asio::awaitable<void> my_coroutine()
  421. * {
  422. * // ...
  423. *
  424. * int result = co_await boost::asio::post(
  425. * []{
  426. * return perform_expensive_computation();
  427. * },
  428. * my_thread_pool);
  429. *
  430. * // handle result on the coroutine's associated executor
  431. * } @endcode
  432. *
  433. * @par Completion Signature
  434. * @code void(decay_t<result_of_t<decay_t<Function>()>>) @endcode
  435. */
  436. template <typename Function, typename Executor,
  437. BOOST_ASIO_COMPLETION_TOKEN_FOR(
  438. void(decay_t<result_of_t<decay_t<Function>()>>)) CompletionToken
  439. = default_completion_token_t<Executor>>
  440. inline auto post(Function&& function, const Executor& ex,
  441. CompletionToken&& token = default_completion_token_t<Executor>(),
  442. constraint_t<
  443. !is_void<result_of_t<decay_t<Function>()>>::value
  444. > = 0,
  445. constraint_t<
  446. (execution::is_executor<Executor>::value
  447. && can_require<Executor, execution::blocking_t::never_t>::value)
  448. || is_executor<Executor>::value
  449. > = 0)
  450. -> decltype(
  451. async_initiate<CompletionToken, void(detail::work_result_t<Function>)>(
  452. declval<detail::initiate_post_with_executor<Executor>>(),
  453. token, static_cast<Function&&>(function)))
  454. {
  455. return async_initiate<CompletionToken, void(detail::work_result_t<Function>)>(
  456. detail::initiate_post_with_executor<Executor>(ex),
  457. token, static_cast<Function&&>(function));
  458. }
  459. /// Submits a function to be run on a specified execution context, and after
  460. /// completion submits the completion handler.
  461. /**
  462. * @param function A nullary function to be executed on the target executor.
  463. *
  464. * @param ctx An execution context, from which the target executor is obtained.
  465. *
  466. * @param token The @ref completion_token that will be used to produce a
  467. * completion handler. The function signature of the completion handler must be:
  468. * @code void handler(); @endcode
  469. *
  470. * @returns <tt>post(forward<Function>(function), ctx.get_executor(),
  471. * forward<NullaryToken>(token))</tt>.
  472. *
  473. * @note If the function object throws an exception, that exception is allowed
  474. * to propagate to the target executor. The behaviour in this case is dependent
  475. * on the executor. For example, boost::asio::io_context will allow the
  476. * exception to propagate to the caller that runs the @c io_context, whereas
  477. * boost::asio::thread_pool will call @c std::terminate.
  478. *
  479. * @par Completion Signature
  480. * @code void() @endcode
  481. */
  482. template <typename Function, typename ExecutionContext,
  483. BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) NullaryToken
  484. = default_completion_token_t<typename ExecutionContext::executor_type>>
  485. inline auto post(Function&& function, ExecutionContext& ctx,
  486. NullaryToken&& token = default_completion_token_t<
  487. typename ExecutionContext::executor_type>(),
  488. constraint_t<
  489. is_void<result_of_t<decay_t<Function>()>>::value
  490. > = 0,
  491. constraint_t<
  492. is_convertible<ExecutionContext&, execution_context&>::value
  493. > = 0)
  494. -> decltype(
  495. async_initiate<NullaryToken, void()>(
  496. declval<detail::initiate_post_with_executor<
  497. typename ExecutionContext::executor_type>>(),
  498. token, static_cast<Function&&>(function)))
  499. {
  500. return async_initiate<NullaryToken, void()>(
  501. detail::initiate_post_with_executor<
  502. typename ExecutionContext::executor_type>(ctx.get_executor()),
  503. token, static_cast<Function&&>(function));
  504. }
  505. /// Submits a function to be run on a specified execution context, and passes
  506. /// the result to a completion handler.
  507. /**
  508. * @param function A nullary function to be executed on the target executor.
  509. *
  510. * @param ctx An execution context, from which the target executor is obtained.
  511. *
  512. * @param token The @ref completion_token that will be used to produce a
  513. * completion handler. The function signature of the completion handler must be:
  514. * @code void handler(); @endcode
  515. *
  516. * @returns <tt>post(forward<Function>(function), ctx.get_executor(),
  517. * forward<CompletionToken>(token))</tt>.
  518. *
  519. * @note If the function object throws an exception, that exception is allowed
  520. * to propagate to the target executor. The behaviour in this case is dependent
  521. * on the executor. For example, boost::asio::io_context will allow the
  522. * exception to propagate to the caller that runs the @c io_context, whereas
  523. * boost::asio::thread_pool will call @c std::terminate.
  524. *
  525. * @par Completion Signature
  526. * @code void(decay_t<result_of_t<decay_t<Function>()>>) @endcode
  527. */
  528. template <typename Function, typename ExecutionContext,
  529. BOOST_ASIO_COMPLETION_TOKEN_FOR(
  530. void(decay_t<result_of_t<decay_t<Function>()>>)) CompletionToken
  531. = default_completion_token_t<typename ExecutionContext::executor_type>>
  532. inline auto post(Function&& function, ExecutionContext& ctx,
  533. CompletionToken&& token = default_completion_token_t<
  534. typename ExecutionContext::executor_type>(),
  535. constraint_t<
  536. !is_void<result_of_t<decay_t<Function>()>>::value
  537. > = 0,
  538. constraint_t<
  539. is_convertible<ExecutionContext&, execution_context&>::value
  540. > = 0)
  541. -> decltype(
  542. async_initiate<CompletionToken, void(detail::work_result_t<Function>)>(
  543. declval<detail::initiate_post_with_executor<
  544. typename ExecutionContext::executor_type>>(),
  545. token, static_cast<Function&&>(function)))
  546. {
  547. return async_initiate<CompletionToken, void(detail::work_result_t<Function>)>(
  548. detail::initiate_post_with_executor<
  549. typename ExecutionContext::executor_type>(ctx.get_executor()),
  550. token, static_cast<Function&&>(function));
  551. }
  552. } // namespace asio
  553. } // namespace boost
  554. #include <boost/asio/detail/pop_options.hpp>
  555. #endif // BOOST_ASIO_POST_HPP