使用 boost::bind 将回调发布到任务队列
Post callbacks to a task queue using boost::bind
>假设我有一个名为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));
}
我没有答案。但是,我已经玩了一个多小时:
-
boost::bind
-
boost::apply<>
-
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
但是,可悲的是,我似乎无法使这件事参数化(正如建议的那样,应该在使用嵌套绑定的合成文档中工作):
// 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));
}
你正在绑定一个函数(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 个参数的重载来伪造。Rvalue refs 也是一种便利,无需多做一点工作即可完成。
- boost::进程间消息队列引发错误
- 避免使用 boost::进程间::消息队列创建文件
- 可以将Boost消息队列文件重定向到用户指定的位置
- Boost 无锁队列断言用于简单的赋值和析构函数
- 在尝试使用boost时断言.跨很多过程中的互动消息队列
- 如何使用boost :: lockfree ::队列实体填充容器
- 使用boost.lockfree队列比使用静音速度慢
- 执行Boost ASIO队列的最大尺寸
- boost消息队列线程安全和进程安全吗?
- 是boost :: asio :: thread_pool线程在多个线程上发布任务时的安全性
- 轮询命令以在 boost asio 中的共享队列中发送
- boost :: lockfree ::队列正在吃我的CPU
- 为什么 Boost 原子使用中的多生产者队列是免等待的
- Poco任务管理器/Boost线程混合和匹配
- boost::进程间消息队列创建时的竞争条件
- boost-asio:用于不同任务的不同线程池
- WinRT C++ 任务队列
- Boost:阻塞,直到队列有另一个项目
- 使用 boost::bind 将回调发布到任务队列
- 具有多个线程的进程之间的Boost消息队列(Boost线程)