asio C++ library

PrevUpHomeNext

experimental::co_composed

Creates an initiation function object that may be used to launch a coroutine-based composed asynchronous operation.

template<
    completion_signature... Signatures,
    typename Implementation,
    typename... IoObjectsOrExecutors>
auto co_composed(
    Implementation && implementation,
    IoObjectsOrExecutors &&... io_objects_or_executors);

The experimental::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.

Parameters

implementation

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.

io_objects_or_executors

Zero or more I/O objects or I/O executors for which outstanding work must be maintained while the operation is incomplete.

Per-Operation Cancellation

By default, per-operation cancellation is disabled for composed operations that use experimental::co_composed. It must be explicitly enabled by calling the state's reset_cancellation_state function.

Examples

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 asio::async_initiate<
    CompletionToken, void(std::error_code)>(
      asio::experimental::co_composed(
        [](auto state, tcp::socket& socket) -> void
        {
          state.reset_cancellation_state(
            asio::enable_terminal_cancellation());

          while (!state.cancelled())
          {
            char data[1024];
            auto [e1, n1] =
              co_await socket.async_read_some(
                asio::buffer(data),
                asio::as_tuple(asio::deferred));

            if (e1)
              co_yield state.complete(e1);

            if (!!state.cancelled())
              co_yield state.complete(
                make_error_code(asio::error::operation_aborted));

            auto [e2, n2] =
              co_await asio::async_write(socket,
                asio::buffer(data, n1),
                asio::as_tuple(asio::deferred));

            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 asio::async_initiate<
    CompletionToken, void(std::error_code)>(
      asio::experimental::co_composed<
        void(std::error_code)>(
          [](auto state, tcp::socket& socket) -> void
          {
            try
            {
              state.throw_if_cancelled(true);
              state.reset_cancellation_state(
                asio::enable_terminal_cancellation());

              for (;;)
              {
                char data[1024];
                std::size_t n = co_await socket.async_read_some(
                    asio::buffer(data), asio::deferred);

                co_await asio::async_write(socket,
                    asio::buffer(data, n), asio::deferred);
              }
            }
            catch (const std::system_error& e)
            {
              co_return {e.code()};
            }
          }, socket),
      token, std::ref(socket));
}
Requirements

Header: asio/experimental/co_composed.hpp

Convenience header: None


PrevUpHomeNext