
On Wed, Dec 19, 2018 at 9:37 PM Sorin Fetche <sorin.fetche@gmail.com> wrote:
And this is what I have in mind:
https://github.com/sorf/cpp-playground/blob/master/source/asio_echo.cpp#L45
Have you considered writing a base class which takes ownership of the user's completion handler and has the necessary hooks? Then you can simply derive from it in your function-level class declaration to get all the hooks. Such a base class might look like this: template<class Handler, class Derived> class operation_base { template<class T, class Executor> friend struct boost::asio::associated_executor; Handler handler_; protected: Handler const& handler() const noexcept { return handler_; } Handler& handler() noexcept { return handler_; } public: operation_base(operation_base&&) = default; operation_base(operation_base const&) = default; operation_base& operator=(operation_base&&) = delete; operation_base& operator=(operation_base const&) = delete; explicit operation_base(Handler&& handler) : handler_(std::move(handler)) { } explicit operation_base(Handler const& handler) : handler_(handler) { } using allocator_type = boost::asio::associated_allocator_t<Handler>; allocator_type get_allocator() const noexcept { return boost::asio::get_associated_allocator(handler_); } template<class Function> friend void asio_handler_invoke(Function&& f, operation_base* op) { using boost::asio::asio_handler_invoke; asio_handler_invoke(f, std::addressof(op->handler_)); } friend bool asio_handler_is_continuation(operation_base* op) { using boost::asio::asio_handler_is_continuation; return asio_handler_is_continuation( std::addressof(op->handler_)); } }; namespace boost { namespace asio { template<class Handler, class Derived, class Executor> struct associated_executor< operation_base<Handler, Derived>, Executor> { using type = typename associated_executor<Handler, Executor>::type; static type get(operation_base<Handler, Derived> const& op, Executor const& ex = Executor()) noexcept { return associated_executor< Handler, Executor>::get(op.handler_, ex); } }; } // asio } // boost Disclaimer: Untested. The class uses CRTP in order for the associated_executor specialization to be selected when passing the derived type. Regards