...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
The any_completion_handler<>
class template can be used to type-erase
completion handlers. This template stores a completion handler in a runtime-polymorphic
wrapper, and forwards the function call operator, associated executor,
associated allocator, and associated cancellation slot to the target handler.
One use case is to enable separate compilation of asynchronous operation implementations. For example, we can declare our implementation function in a header file, and provide a thin asynchronous operation wrapper:
void async_sleep_impl( boost::asio::any_completion_handler<void(boost::system::error_code)> handler, boost::asio::any_io_executor ex, std::chrono::nanoseconds duration); template <typename CompletionToken> inline auto async_sleep(boost::asio::any_io_executor ex, std::chrono::nanoseconds duration, CompletionToken&& token) { return boost::asio::async_initiate< CompletionToken, void(boost::system::error_code)>( async_sleep_impl, token, std::move(ex), duration); }
By wrapping a call to async_initiate
,
the async_sleep
template
function adds full support for completion tokens. The definition of async_sleep_impl
is then put into a separately
compiled source file:
void async_sleep_impl( boost::asio::any_completion_handler<void(boost::system::error_code)> handler, boost::asio::any_io_executor ex, std::chrono::nanoseconds duration) { auto timer = std::make_shared<boost::asio::steady_timer>(ex, duration); timer->async_wait(boost::asio::consign(std::move(handler), timer)); }
Another use for any_completion_handler<>
is to vary the implementation behind
an asynchronous operation at runtime, by using virtual functions:
class line_reader { public: // ... template <typename CompletionToken> auto async_read_line(std::string prompt, CompletionToken&& token) { return boost::asio::async_initiate< CompletionToken, void(boost::system::error_code, std::string)>( [](auto handler, line_reader* self, std::string prompt) { self->async_read_line_impl(std::move(prompt), std::move(handler)); }, token, this, prompt); } private: virtual void async_read_line_impl(std::string prompt, boost::asio::any_completion_handler< void(boost::system::error_code, std::string)> handler) = 0; };
A derived class provides the implementation of the operation:
class stdin_line_reader : public line_reader { private: // ... void async_read_line_impl(std::string prompt, boost::asio::any_completion_handler< void(boost::system::error_code, std::string)> handler) override { // ... } };
any_completion_handler, type erasure examples (C++11), type erasure examples (C++20).