假设我有一个名为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));
}
答案 0 :(得分:5)
我没有回答。但是,我玩了一个多小时了:
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
但是,遗憾的是,我似乎无法将此事件参数化(如建议应在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));
}
答案 1 :(得分:5)
您绑定了一个本身进行绑定的函数(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也是一种便利,无需多花一些工作即可完成。