When synchronously or asynchronously accepting a new connection, but
without specifying an executor or execution context, the accept
operation will now correctly propagate the executor type from the
acceptor to the socket. For example, if your acceptor type is:
basic_socket_acceptor<ip::tcp, my_executor_type>
then your accepted socket type will be:
basic_stream_socket<ip::tcp, my_executor_type>
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 asynchronous operations' initiation function objects now report
their associated I/O executor via the nested type `executor_type` and
member function `get_executor()`.
The presence of `executor_type` and `get_executor()` should be treated
as optional, and consequently it may be preferable to access them via
the `associated_executor` trait and the `get_associated_executor()`
helper function.
The I/O objects provided by Asio now support the nested template type
`rebind_executor` as a way to generically rebind them to an alternative
I/O executor type. For example:
using my_socket_type =
tcp::socket::rebind_executor<my_executor_type>::other;
This change introduces three new concepts:
* completion_signature<T>: Checks if T is a signature of the form R(Args...).
* completion_handler_for<T, Signature>: Checks if T is usable as a completion
handler with the specified signature.
* completion_token_for<T, Signature>: Checks if T is a completion token that
can be used with async_initiate and the specified signature.
For backward compatibility, use the macros BOOST_ASIO_COMPLETION_SIGNATURE,
BOOST_ASIO_COMPLETION_HANDLER_FOR, and BOOST_ASIO_COMPLETION_TOKEN_FOR
respectively. These macros expand to `typename` when concepts are unsupported.
C++14 or later is required to support completion tokens that use
per-operation return type deduction. For C++11 or earlier, a completion
token's async_result specialisation must still provide the nested
typedef `return_type`.
Although MSVC 11.0 supports the decltype keyword, it does not operate
correctly when used in the buffer sequence detection traits. This change
fixes compile errors when trying to use the read and write composed
operations with MSVC 11.0.
This change adds a new set of type requirements for dynamic buffers,
DynamicBuffer_v2, which supports copy construction. These new type
requirements enable dynamic buffers to be used as arguments to
user-defined composed operations, where the same dynamic buffer object
is used repeatedly for multiple underlying operations. For example:
template <typename DynamicBuffer>
void echo_line(tcp::socket& sock, DynamicBuffer buf)
{
n = boost::asio::read_until(sock, buf, '\n');
boost::asio::write(sock, buf, boost::asio::transfer_exactly(n));
}
The original DynamicBuffer type requirements have been renamed to
DynamicBuffer_v1.
New type traits is_dynamic_buffer_v1 and is_dynamic_buffer_v2 have been
added to test for conformance to DynamicBuffer_v1 and DynamicBuffer_v2
respectively. The existing is_dynamic_buffer trait has been retained and
delegates to is_dynamic_buffer_v1, unless BOOST_ASIO_NO_DYNAMIC_BUFFER_V1
is defined, in which case it delegates to is_dynamic_buffer_v2.
The dynamic_string_buffer and dynamic_vector buffer classes conform to
both DynamicBuffer_v1 and DynamicBuffer_v2 requirements.
When BOOST_ASIO_NO_DYNAMIC_BUFFER_V1 is defined, all support for
DynamicBuffer_v1 types and functions is #ifdef-ed out. Support for using
basic_streambuf with the read, async_read, read_until, async_read_until,
write, and async_write functions is also disabled as a consequence.
This change should have no impact on existing source code that simply
uses dynamic buffers in conjunction with asio's composed operations,
such as:
string data;
// ...
size_t n = boost::asio::read_until(my_socket
boost::asio::dynamic_buffer(data, MY_MAX),
'\n');