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.
The awaitable<>, co_spawn(), this_coro, detached, and redirect_error
facilities have been moved from the asio::experimental namespace to
namespace asio. As part of this change, the this_coro::token() awaitable
has been superseded by the asio::use_awaitable completion token.
Please note that the use_awaitable and redirect_error completion tokens
work only with asynchronous operations that use the new form of
async_result with member function initiate(). Furthermore, when using
use_awaitable, please be aware that the asynchronous operation is not
initiated until co_await is applied to the awaitable<>.
All I/O objects now have an additional Executor template parameter. This
template parameter defaults to the asio::executor type (the polymorphic
executor wrapper) but can be used to specify a user-defined executor
type.
I/O objects' constructors and functions that previously took an
asio::io_context& now accept either an Executor or a reference to a
concrete ExecutionContext (such as asio::io_context or
asio::thread_pool).
One potential point of breakage in existing user code is when reusing an
I/O object's io_context for constructing another I/O object, as in:
asio::steady_timer my_timer(my_socket.get_executor().context());
To fix this, either construct the second I/O object using the first I/O
object's executor:
asio::steady_timer my_timer(my_socket.get_executor());
or otherwise explicitly pass the io_context:
asio::steady_timer my_timer(my_io_context);
N.B. The Windows-specific tick_count_timer example has been removed as
it has been superseded by timers based on the standard steady_clock.
It's also not clear how to map a wrapping time source to the standard
chrono concepts.
Define BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM to enable the
old Boost.Date_Time interface in basic_socket_streambuf and
basic_socket_iostream.
* Use asio::steady_timer rather than asio::deadline_timer.
* Use asio::dynamic_buffer rather than asio::streambuf.
* Use timed asio::io_context::run_for() function for blocking clients.
* Add example showing a custom completion token for blocking with timeouts.