Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Post callbacks to a task queue using boost::bind

Suppose I have a function called subscribe() that takes a callback handler, which will be called when the event is triggered.

Now, I have another version, called subscribe2(). Everything is the same except that, when triggered, it needs to post it to an event queue. It is implemented using the original subscribe(), with a helper funciton called helper(). All it does is to bind the original handler and whatever additional arguments into a functor, and call postToEventQueue().

Now, I wonder if there's a way to eliminate the helper function, so that in subsribe2(), I can somehow package the postToTaskQueue() function and the original callback handler directly, and pass it to subscribe(). The reason is that I have a lot of different handler types, and it is tedious and tiring to introduce helper function all over the place. Afterall, boost::bind is supposed to return a new function given the original function, right? I am trying to generate the helper function directly with boost::bind.

One attempt is to say

subscribe(boost::bind(boost::bind(postToTaskQueue, boost::bind(_1, _2)), cb, _1)); 

in subscribe2(), but it doesn't work. Is it possible at all?

Please see detailed example code below. Thanks!

#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <iostream>

typedef boost::function<void(int)> SomeCallback;
typedef boost::function<void()> Task;

void handler(int i){
 std::cout << "i=" << i <<std::endl;
}

void subscribe(SomeCallback cb)
{
  cb(100);  //just invoke the callback for simplicity
}

void postToTaskQueue(Task t)
{
   t();  // just invoke the task for simplicity
}

void helper(SomeCallback cb, int i)
{
   Task t = boost::bind(cb, i);
   postToTaskQueue(t);
}

void subscribe2(SomeCallback cb)
{
  subscribe(boost::bind(helper, cb, _1));

  // this does not work..
  // subscribe(boost::bind(boost::bind(postToTaskQueue, boost::bind(_1, _2)), cb, _1)); 
}
int main()
{
  subscribe(boost::bind(handler, _1));
  subscribe2(boost::bind(handler, _1));
}
like image 525
ttrrxx Avatar asked Dec 25 '22 21:12

ttrrxx


1 Answers

I have no answer. However, I've played with this for over an hour:

  • boost::bind
  • boost::apply<>
  • boost::protect

Maybe, just maybe, a more experienced boost developer could take it from here:

void subscribe2(SomeCallback cb)
{
    using boost::bind;
    using boost::protect;
    using boost::apply;

    bind(cb, 41)(); // OK of course
    postToTaskQueue(bind(cb, 46)); // also fine
    bind(postToTaskQueue, protect(bind(cb, 146)))(); // boost::protect to the rescue

    postToTaskQueue(bind(apply<void>(), cb, 47));
    bind(postToTaskQueue, protect(bind(apply<void>(), cb, 147)))();

The above prints

i=41
i=46
i=146
i=47
i=147

But, sadly, I can't seem to make this this thing parameterizing (as suggested should work in the documentation on composition using Nested Binds):

    // but sadly, this appears to not work ...
    auto hmm = bind(postToTaskQueue, bind(apply<void>(), cb, _1));
    hmm(997); // FAIL
}

Here's a fully compiled demo showing the state of affairs: Live on Coliru

#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/bind/protect.hpp>
#include <boost/bind/apply.hpp>
#include <iostream>

typedef boost::function<void(int)> SomeCallback;
typedef boost::function<void()>    Task;

void handler(int i){
    std::cout << "i=" << i <<std::endl;
}

void subscribe(SomeCallback cb)
{
    cb(100);  //just invoke the callback for simplicity
}

void postToTaskQueue(Task t)
{
    t();  // just invoke the task for simplicity
}

void helper(SomeCallback cb, int i)
{
    postToTaskQueue(boost::bind(cb, i));
}

void subscribe2(SomeCallback cb)
{
    using boost::bind;
    using boost::protect;
    using boost::apply;

    bind(cb, 41)(); // OK of course
    postToTaskQueue(bind(cb, 46)); // also find
    bind(postToTaskQueue, protect(bind(cb, 146)))(); // boost::protect to the rescue

    postToTaskQueue(bind(apply<void>(), cb, 47));
    bind(postToTaskQueue, protect(bind(apply<void>(), cb, 147)))();

    // but sadly, this appears to not work ...
    auto hmm = bind(postToTaskQueue, bind(apply<void>(), cb, _1));
    //hmm(997); // FAIL
}
int main()
{
    subscribe (boost::bind(handler, _1));
    subscribe2(boost::bind(handler, _1));
}
like image 70
sehe Avatar answered Feb 28 '23 16:02

sehe