This means that use_coro does not return a coro object, just like
use_awaitable does, i.e. it's an overhead that buys us type erasure.
Allocators can now be set for coro by including allocator_arg in the
coro signature.
Added new overloads of experimental::make_parallel_group that may be used
to launch a dynamically-sized set of asynchronous operations, where all
operations are the same type. For example:
using op_type = decltype(
socket1.async_read_some(
boost::asio::buffer(data1),
boost::asio::deferred
)
);
std::vector<op_type> ops;
ops.push_back(
socket1.async_read_some(
boost::asio::buffer(data1),
boost::asio::deferred
)
);
ops.push_back(
socket2.async_read_some(
boost::asio::buffer(data2),
boost::asio::deferred
)
);
boost::asio::experimental::make_parallel_group(ops).async_wait(
boost::asio::experimental::wait_for_all(),
[](
std::vector<std::size_t> completion_order,
std::vector<boost::system::error_code> e,
std::vector<std::size_t> n
)
{
for (std::size_t i = 0; i < completion_order.size(); ++i)
{
std::size_t idx = completion_order[i];
std::cout << "socket " << idx << " finished: ";
std::cout << e[idx] << ", " << n[idx] << "\n";
}
}
);
Thanks go to Klemens Morgenstern for supplying part of this implementation.
The consign completion token adapter can be used to attach additional
values to a completion handler. This is typically used to keep at least
one copy of an object, such as a smart pointer, alive until the
completion handler is called.
For example:
auto timer1 = std::make_shared<boost::asio::steady_timer>(my_io_context);
timer1->expires_after(std::chrono::seconds(1));
timer1->async_wait(
boost::asio::consign(
[](boost::system::error_code ec)
{
// ...
},
timer1
)
);
auto timer2 = std::make_shared<boost::asio::steady_timer>(my_io_context);
timer2->expires_after(std::chrono::seconds(30));
std::future<void> f =
timer2->async_wait(
boost::asio::consign(
boost::asio::use_future,
timer2
)
);
Added new spawn() overloads that conform to the requirements for
asynchronous operations. These overloads also support cancellation. When
targeting C++11 and later these functions are implemented in terms of
Boost.Context directly.
The existing overloads have been retained but are deprecated.
The completion_signature_of trait (and corresponding type alias
completion_signature_of_t) may be used to determine the completion
signature of an asynchronous operation. For example:
auto d = my_timer.async_wait(asio::deferred);
using sig = asio::completion_signature_of<decltype(d)>::type;
// sig is void(error_code)
or with a handcrafted asynchronous operation:
struct my_async_op
{
asio::ip::tcp::socket& socket_ = ...;
template <typename Token>
auto operator()(asio::const_buffer data, Token&& token)
{
return asio::async_write(socket_, data,
std::forward<Token>(token));
}
};
using sig =
asio::completion_signature_of<
my_async_op, asio::const_buffer>::type;
// sig is void(error_code, size_t)
The is_async_operation trait may be used to determine if a function
object, and optional arguments, may be called to initiate an
asynchronous operation. For example, when using asio::deferred
auto d = my_timer.async_wait(asio::deferred);
static_assert(asio::is_async_operation<decltype(d)>::value);
or with a handcrafted asynchronous operation:
struct my_async_op
{
asio::ip::tcp::socket& socket_ = ...;
template <typename Token>
auto operator()(asio::const_buffer data, Token&& token)
{
return asio::async_write(socket_, data,
std::forward<Token>(token));
}
};
static_assert(
asio::is_async_operation<
my_async_op, asio::const_buffer>::value);
This is no longer an experimental facility. The names deferred and
deferred_t have been temporarily retained as deprecated entities under
the asio::experimental namespace, for backwards compatibility.