Boost logo

Boost Users :

Subject: Re: [Boost-users] [Asio/Beast] Any non-obvious reasons for no bind_executor_and_allocator?
From: Vinnie Falco (vinnie.falco_at_[hidden])
Date: 2018-12-20 06:24:23


On Wed, Dec 19, 2018 at 9:37 PM Sorin Fetche <sorin.fetche_at_[hidden]> 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


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net