Every I/O executor type now has an associated default completion token
type. This is specified via the `default_completion_token_type` trait.
This trait may be used in asynchronous operation declarations as
follows:
template <
typename IoObject,
typename CompletionToken =
typename default_completion_token_type<
typename IoObject::executor_type
>::type
>
auto async_foo(
IoObject& io_object,
CompletionToken&& token =
typename default_completion_token_type<
typename IoObject::executor_type
>::type{}
);
If not specialised, this trait type is `void`, meaning no default
completion token type is available for the given I/O executor.
The `default_completion_token_type` trait is specialised for the
`use_awaitable` completion token so that it may be used as shown in the
following example:
auto socket = use_awaitable.as_default_on(tcp::socket(my_context));
// ...
co_await socket.async_connect(my_endpoint); // Defaults to use_awaitable.
In this example, type of the `socket` object is transformed from
`tcp::socket` to have an I/O executor with the default completion token
set to `use_awaitable`.
Alternatively, the socket type may be computed directly:
using tcp_socket = use_awaitable_t<>::as_default_on_t<tcp::socket>;
tcp_socket socket(my_context);
// ...
co_await socket.async_connect(my_endpoint); // Defaults to use_awaitable.