On Wed, Dec 19, 2018 at 9:37 PM Sorin Fetche 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 operation_base
{
template
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
struct associated_executor<
operation_base, Executor>
{
using type = typename
associated_executor::type;
static type get(operation_base 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