...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
Creates an initiation function object that may be used to launch a coroutine-based composed asynchronous operation.
template< typename... Signatures, typename Implementation, typename... IoObjectsOrExecutors> auto co_composed( Implementation && implementation, IoObjectsOrExecutors &&... io_objects_or_executors);
The co_composed utility simplifies the implementation of composed asynchronous
operations by automatically adapting a coroutine to be an initiation function
object for use with async_initiate
.
When awaiting asynchronous operations, the coroutine automatically uses a
conforming intermediate completion handler.
A function object that contains the coroutine-based implementation
of the composed asynchronous operation. The first argument to the function
object represents the state of the operation, and may be used to test
for cancellation. The remaining arguments are those passed to async_initiate
after the completion
token.
Zero or more I/O objects or I/O executors for which outstanding work must be maintained while the operation is incomplete.
By default, terminal per-operation cancellation is enabled for composed operations
that use co_composed. To disable cancellation for the composed operation,
or to alter its supported cancellation types, call the state's reset_cancellation_state
function.
The following example illustrates manual error handling and explicit checks
for cancellation. The completion handler is invoked via a co_yield
to the state's complete
function,
which never returns.
template <typename CompletionToken> auto async_echo(tcp::socket& socket, CompletionToken&& token) { return boost::asio::async_initiate< CompletionToken, void(boost::system::error_code)>( boost::asio::co_composed( [](auto state, tcp::socket& socket) -> void { state.reset_cancellation_state( boost::asio::enable_terminal_cancellation()); while (!state.cancelled()) { char data[1024]; auto [e1, n1] = co_await socket.async_read_some( boost::asio::buffer(data)); if (e1) co_yield state.complete(e1); if (!!state.cancelled()) co_yield state.complete( make_error_code(boost::asio::error::operation_aborted)); auto [e2, n2] = co_await boost::asio::async_write(socket, boost::asio::buffer(data, n1)); if (e2) co_yield state.complete(e2); } }, socket), token, std::ref(socket)); }
This next example shows exception-based error handling and implicit checks
for cancellation. The completion handler is invoked after returning from
the coroutine via co_return
.
Valid co_return
values are
specified using completion signatures passed to the co_composed
function.
template <typename CompletionToken> auto async_echo(tcp::socket& socket, CompletionToken&& token) { return boost::asio::async_initiate< CompletionToken, void(boost::system::error_code)>( boost::asio::co_composed< void(boost::system::error_code)>( [](auto state, tcp::socket& socket) -> void { try { state.throw_if_cancelled(true); state.reset_cancellation_state( boost::asio::enable_terminal_cancellation()); for (;;) { char data[1024]; std::size_t n = co_await socket.async_read_some( boost::asio::buffer(data)); co_await boost::asio::async_write(socket, boost::asio::buffer(data, n)); } } catch (const boost::system::system_error& e) { co_return {e.code()}; } }, socket), token, std::ref(socket)); }
Header: boost/asio/co_composed.hpp
Convenience header: boost/asio.hpp