The experimental::deferred completion token takes a call to an
asynchronous operation's initiating function and turns it into a
function object that accepts a completion token. For example:
auto deferred_op =
timer.async_wait(
boost::asio::experimental::deferred);
...
std::move(deferred_op)(
[](std::error_code ec){ ... });
or
auto deferred_op =
timer.async_wait(
boost::asio::experimental::deferred);
...
std::future<void> =
std::move(deferred_op)(
boost::asio::use_future);
The deferred token also supports chaining, to create simple
compositions:
auto deferred_op =
timer.async_wait(
boost::asio::experimental::deferred(
[&](std::error_code ec)
{
timer.expires_after(
std::chrono::seconds(1));
return timer.async_wait(
boost::asio::experimental::deferred);
});
...
std::future<void> = std::move(deferred_op)(boost::asio::use_future);
When using standard executors, work is tracked by requiring (or
preferring) an executor with the execution::outstanding_work.tracked
property. This replaces executor_work_guard and make_work_guard() with
code of the form
asio::io_context io_context;
auto work = asio::require(io_context.get_executor(),
asio::execution::outstanding_work.tracked);
To explicitly reset work, store the returned work-tracking executor in
an any_io_executor object:
asio::any_io_executor work
= asio::require(io_context.get_executor(),
asio::execution::outstanding_work.tracked);
and then assign an empty executor into the object when done:
work = asio::any_io_executor();