On Wed, Dec 19, 2018 at 10:24 PM Vinnie Falco wrote:
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?
<snip> Yes, the base class is a very good idea. It helps reduce the boilerplate in the composed operation and the risk of moving `this` before accessing things in it. Here's how its usage looks like to implement the composed operation: https://github.com/sorf/cpp-playground/blob/master/source/asio_echo_v2.cpp#L... \code struct internal_state : public state_base { /*...*/ static void async_echo(internal_state&& self) { auto read_buffer = asio::buffer(self.echo_buffer); self.socket.async_read_some( read_buffer, self.wrap()([self = std::move(self)](error_code ec, std::size_t bytes) mutable { if (!ec) { /*...*/ } else { self.call_handler(ec, bytes); } })); } void call_handler(error_code ec, std::size_t bytes) { /* Deallocate derived state resources */ this->call_handler_base(ec, bytes); } \endcode I still don't like the risk of moving `this` (or `self`) before members in the derived class are used to initiate the next operation (e.g. the echo_buffer). On Wed, Dec 19, 2018 at 10:24 PM Vinnie Falco wrote:
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; <snip> template<class Function> friend void asio_handler_invoke(Function&& f, operation_base* op) <snip> friend bool asio_handler_is_continuation(operation_base* op)
It looks like the base class doesn't even need these hooks, at least not directly. The object returned by asio::bind_executor and its equivalent for allocator, which doesn't exist yet, should have them. I'll take a shot at this in the next version of the example code. Best regards