multiple levels of bind nesting
I have some code that implements an asynchronous worker model where a client calls some function to request an asynchronous operation and passes a callback function, whose type is determined by a template parameter. e.g. class worker { template<class Handler> void async_do_work(Handler h) { ... } }; class client { void start_work(); void work_finished(boost::system::error_code ec, size_t bytes_transferred); }; However there are many classes implementing async_do_work but which do the work in a different way. For this I use a boost::variant for each type and use a boost::static_visitor to delegate to the appropriate async_do_work method. This uses code such as the following: void client::start_work() { apply_visitor( bind(do_work_visitor(), _1, protect(bind(&client::work_finished, this, _1, _2))) , work_variant_); } So from async_do_work's point of view, it receives a function with 2 arguments. How async_do_work operates internally should be separated from the client. It may not even use another thread, or it may combine the efforts of multiple threads to achieve the result. So because of that, I want async_do_work to intercept the callback before it gets posted back to the original caller. To do this, I tried the following in the implementation of worker: class worker { public: template<class Handler> void async_do_work(Handler h) { //impl supports the same basic interface as worker impl->async_do_work( bind(&worker::intercept_handler<Handler>, this, h, _1, _2)); } private: template<class Handler> void intercept_handler(Handler real_handler, boost::system::error_code ec, size_t bytes_transferred) { //do whatever is necessary and then call the real handler. real_handler(ec, bytes_transferred); } }; However this doesn't work. I've also tried protect(bind in the async_do_work function and that doesn't work either. Is it supposed to be possible to nest binds arbitrarily deep or is this just a limitation? Or am I just doing it wrong? Regards
On Wed, Jul 22, 2009 at 9:29 AM, Zachary Turner
template<class Handler> void intercept_handler(Handler real_handler, boost::system::error_code ec, size_t bytes_transferred) { //do whatever is necessary and then call the real handler.
real_handler(ec, bytes_transferred); }
What you're doing should work in principle, what errors are you getting? By the way, have you considered using boost::function for the callbacks? That way you could do all this without templates, so you can hide the implementation in a cpp file. Also, the type of the parameters of the callback would be fixed and the compiler will give you (and users) better error messages. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode
AMDG Zachary Turner wrote:
<snip>
void client::start_work() { apply_visitor( bind(do_work_visitor(), _1, protect(bind(&client::work_finished, this, _1, _2))) , work_variant_); } <snip>
template<class Handler> void async_do_work(Handler h) { //impl supports the same basic interface as worker
impl->async_do_work( bind(&worker::intercept_handler<Handler>, this, h, _1, _2)); }
Since h is a bind expression it needs to be protect'ed.
<snip> However this doesn't work. I've also tried protect(bind in the async_do_work function and that doesn't work either. Is it supposed to be possible to nest binds arbitrarily deep or is this just a limitation? Or am I just doing it wrong?
In Christ, Steven Watanabe
On Wed, Jul 22, 2009 at 4:04 PM, Steven Watanabe
AMDG
Zachary Turner wrote:
<snip>
void client::start_work() { apply_visitor( bind(do_work_visitor(), _1, protect(bind(&client::work_finished, this, _1, _2))) , work_variant_); } <snip>
template<class Handler> void async_do_work(Handler h) { //impl supports the same basic interface as worker
impl->async_do_work( bind(&worker::intercept_handler<Handler>, this, h, _1, _2)); }
Since h is a bind expression it needs to be protect'ed.
Yes I tried that as well but was not able to get it working. Anyway I never got it to work but I tried Emil's suggestion of using boost::function and that fixed the problem. I'm sure I was just doing something wrong, or perhaps dealing with compiler non-comformance issues, but the error messages are very difficult to diagnose sometimes, and will sometimes appear on functions that are not even the one causing the problem. In this case for example the error referred to the apply_visitor() line of code and there was no mention in the error logs of the line of code containing the bind inside of async_do_work, even though that was clearly where the problem was.
Zachary Turner wrote: [snip]
Yes I tried that as well but was not able to get it working. [snip]
I managed to get something similar working, by making the protected type explicit. Please see the code snippet below. Kind regards, Rutger template< typename Something > class some_class { typedef some_class<Something> this_type; template< typename Handler > void func_a( ..., Handler handler ) { async_something( ..., boost::bind( &this_type::template func_b< boost::_bi::protected_bind_t<Handler> >, this, ..., boost::protect(handler) ) ); } template < typename Handler > void func_b( ..., Handler ) { } };
[snip]
Yes I tried that as well but was not able to get it working. [snip]
I managed to get something similar working, by making the protected type explicit. Please see the code snippet below.
Kind regards,
Rutger
Hi all, Another solution : passing the handler using a boost::tuple. http://www.boost.org/doc/libs/1_39_0/doc/html/boost_asio/example/serializati... The functions connection::async_read and connection::handle_read_header describe how to do. Does one of this two solutions offer better performances ? (Am I off topic ?) Regards, Adrien Panay
participants (5)
-
Adrien Panay
-
Emil Dotchevski
-
Rutger ter Borg
-
Steven Watanabe
-
Zachary Turner