Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

Type Erasure, Separate Compilation and Virtual Functions

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
  {
    // ...
  }
};
See Also

any_completion_handler, type erasure examples (C++11), type erasure examples (C++20).


PrevUpHomeNext