我尝试使用VC11和g 4.7.2编译以下示例:
#include <functional>
class X {
public:
template <typename T>
explicit X(T t)
{
std::bind(&X::invoke<T>, this, t)();
}
private:
template <typename T>
void invoke(T t)
{
t();
}
};
class Y {
public:
void foo() {
//...
}
};
int main() {
Y y;
X x(std::bind(&Y::foo, &y));
return 0;
}
但它完成了错误 . 我不确定粘贴整个编译器输出是否合理,但一般情况下
vc11说:
错误C2664:'void std :: _ Pmf_wrap :: operator()(_ Farg0&,_ V0_t)const':无法将参数3从'void'转换为'std :: _ Bind,Y *,std :: _ Nil,std :: _Nil,std :: _ Nil,std :: _ Nil,std :: _ Nil,std :: _ Nil>'c:\ program files(x86)\ microsoft visual studio 11.0 \ vc \ include \ functional 1152 1 ConsoleApplication1(Microsoft Visual C Compiler 2012年11月CTP)
和g:
编译完成时出现错误:source.cpp:在实例化'X :: X(T)[with T = std :: _ Bind(Y *)>]'时:source.cpp:28:33:从这里获取源代码 . cpp:8:9:错误:无法调用'(std :: _ Bind_helper(Y *)>),X * const,std :: _ Bind(Y *)>&> :: type {aka std :: _ Bind (Y *)>)>(X *,std :: _ Bind(Y *)>)>})()'
有没有办法解决这个问题 . 保存主要思想对于我来说非常重要 - 可以用任何可调用对象(函数对象,函数指针或 std::bind()
函数返回的调用包装器)实例化的类 .
如果有人帮忙,我将不胜感激 .
附:如果我创建 X
的实例,它会编译,传递函数对象或函数指针 .
2 回答
问题的根本原因似乎是
std::bind
执行其参数的内部复制,特别是t
.您可能希望以这种方式解决它:
这也可以,但是你不会允许
bind
的结果超过参数t
(否则,你会将悬空引用传递给invoke<T>()
):UPDATE:
上述解决方案是有助于实现您在示例中显示的内容的解决方法 . 但是,从评论中可以看出,您的用例可能大不相同(例如,传递
bind
的结果以供以后评估) .正如Maxim Yegorushkin在他的回答中正确指出的那样,概念上正确的解决方案在于使用诸如Boost的
protect
之类的构造 .如果您不想使用Boost,使用C 11的可变参数模板定义您自己的
protect()
函数非常容易:最终,这是你在课堂上使用它的方式,正如Maxim建议的那样:
我认为他们在
std::bind
中采用boost::bind
时忽略了重要的一点,即boost::protect()
. 您的代码可以修复如下:或者,或者:
见http://www.boost.org/doc/libs/1_53_0/libs/bind/bind.html
Scott Meyers即将推出的Effective C++11: Content and Status将建议首选lambdas到std :: bind . 在C 11中你可以简单地做到: