Am Mo., 9. Sept. 2019 um 09:03 Uhr schrieb Gavin Lambert via Boost-users <boost-users@lists.boost.org>:

> It can be called without an argument (for kick-off), with a single error_code (from async_wait)  or with two argiments (from async_read).

Yes, that's the method the OP is currently using.  It requires using a
coroutine or other state to determine which "step" you're up to, whereas
with separate overloads this is inherent in which method is being called.

Neither approach is necessarily "better" than the other; it depends what
you're doing in there as to which one ends up being more readable.

Well, I got both implementations (async timed connect and socks4 handshake in place now and I do prefer the coroutine approach as it is much easier to read and I wanted to adapt this to more functions very soon.

The problem really are the different handler signatures. Those default arguments are not a silver bullet by any means. I have managed to get it done using beast::bind_handler() in my timed_connect impl but pretty much the identical code failed entirely in the socks4 handshake.
I can now only assume that using bind_handler() with the move_ahead pattern simply doesn't work and without any kind of bind_handler you will quickly run out of ways to order the arguments in operator() to fit all functions.

In any case, I am glad I got the impl as far as this and that's a great step forward in re-using code in my projects.

Thanks for all your suggestions,

Stephan