【问题标题】:Post callbacks to a task queue using boost::bind使用 boost::bind 将回调发布到任务队列
【发布时间】:2013-09-08 03:31:46
【问题描述】:

假设我有一个名为subscribe() 的函数,它接受一个回调处理程序,该处理程序将在事件触发时调用。

现在,我有另一个版本,名为 subscribe2()。一切都是一样的,只是在触发时,它需要将其发布到事件队列中。它是使用原始的subscribe() 实现的,并带有一个名为helper() 的辅助函数。它所做的只是将原始处理程序和任何其他参数绑定到函子中,然后调用postToEventQueue()

现在,我想知道是否有办法消除辅助函数,以便在subsribe2() 中,我可以以某种方式直接将postToTaskQueue() 函数和原始回调处理程序打包,并将其传递给subscribe()。原因是我有很多不同的处理程序类型,到处引入辅助函数既乏味又累人。毕竟, boost::bind 应该在给定原始函数的情况下返回一个新函数,对吧?我正在尝试使用 boost::bind 直接生成辅助函数。

一种尝试是说

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

subscribe2(),但它不起作用。有可能吗?

请参阅下面的详细示例代码。谢谢!

#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));
}

【问题讨论】:

    标签: c++ boost-bind boost-function boost-phoenix boost-lambda


    【解决方案1】:

    我没有答案。但是,我已经玩了一个多小时了:

    • boost::bind
    • boost::apply&lt;&gt;
    • boost::protect

    也许,只是也许,一个更有经验的提升开发者可以从这里获得它:

    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)))();
    

    以上打印件

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

    但是,遗憾的是,我似乎无法将这个东西参数化(建议应该在 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
    }
    

    这是一个完整编译的演示,显示了事态: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));
    }
    

    【讨论】:

      【解决方案2】:

      您正在绑定一个本身执行绑定的函数 (helper)。这意味着您正在(间接)绑定bind 本身。这是关键的洞察力。解决方案是编写一个可以自身绑定的小bind 函数对象包装器。这是我的解决方案的样子:

      #include <utility>
      #include <iostream>
      #include <boost/function.hpp>
      #include <boost/phoenix/bind.hpp>
      #include <boost/phoenix/core/argument.hpp>
      using boost::phoenix::placeholders::_1;
      typedef boost::function<void(int)> SomeCallback;
      typedef boost::function<void()> Task;
      
      struct bind_t
      {
          template<typename Sig>
          struct result;
      
          template<typename This, typename ...A>
          struct result<This(A...)>
          {
              typedef decltype(boost::phoenix::bind(std::declval<A>()...)) type;
          };
      
          template<typename ...A>
          auto operator()(A &&...a) const -> decltype(boost::phoenix::bind(std::forward<A>(a)...))
          {
              return boost::phoenix::bind(std::forward<A>(a)...);
          }
      };
      
      bind_t const bind = {};
      
      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 subscribe2(SomeCallback cb)
      {
          subscribe(bind(postToTaskQueue, bind(bind, cb, _1)));
      }
      
      int main()
      {
          subscribe(::bind(handler, _1));
          subscribe2(::bind(handler, _1));
      }
      

      我切换到 Phoenix 的 bind,因为它可以让你绑定多态函数对象(上面的 bind 是)。

      此解决方案需要decltype。它还使用可变参数,但可以通过最多 N 个参数的重载来伪造。右值引用也是一种方便,无需多做一些工作即可完成。

      【讨论】:

      • 我怎么会错过这个答案。我喜欢你的解释(经常如此),虽然它仍然需要“帮助者”,但至少它只使用通用的、可重用的。
      猜你喜欢
      • 2013-02-17
      • 1970-01-01
      • 1970-01-01
      • 2012-12-03
      • 2018-11-26
      • 2015-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多