如何绑定传递未指定调用包装器的成员函数模板
How do I bind a member function template passing unspecified call wrapper
我尝试使用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,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil>' c:program files (x86)microsoft visual studio 11.0vcincludefunctional 1152 1 ConsoleApplication1 (microsoft visual c++ Compiler Nov 2012 CTP)
和g + +:
编译结束时出现错误:
source.cpp:在实例化'X::X(T) [with T = std::_Bind(Y*)>]':
Source.cpp:28:33: required from here
source.cpp: 9:错误:无法与调用的(std:: _Bind_helper (Y *)>), X * const std:: _Bind (Y *)>,>::类型{aka std:: _Bind (Y *)>)> (X *, std:: _Bind (Y *)>)>}) ()'
有办法解决这个问题吗?这对我来说非常重要,保存主要思想-一个可以用任何可调用对象(函数对象,函数指针或std::bind()
函数返回的调用包装器)实例化的类。
如果有人帮忙,我将非常感激。
注:如果我创建X
的实例,传递函数对象或函数指针,它会编译
我认为他们在将boost::bind
引入std::bind
时遗漏了一个重要的部分,即boost::protect()
。您的代码可以像下面这样修复:
#include <boost/bind/protect.hpp>
// ...
X x(boost::protect(std::bind(&Y::foo, &y)));
,或者另外:
template <typename T>
explicit X(T t)
{
auto tt = boost::protect(t);
auto f = std::bind(&X::invoke<decltype(tt)>, this, tt);
f();
}
见http://www.boost.org/doc/libs/1_53_0/libs/bind/bind.html
虽然默认情况下第一个参数不被求值,但所有其他参数都被求值。有时不需要对第一个参数之后的参数求值,即使它们是嵌套的绑定子表达式。这可以在另一个函数对象protect的帮助下实现,它掩盖了类型,这样bind就不能识别和计算它。当被调用时,protect只是将参数列表不加修改地转发给另一个函数对象。
头文件boost/bind/protect.hpp包含了一个protect的实现。要保护bind函数对象不被求值,可以使用protect(bind(f,…))。
Scott Meyers即将出版的Effective c++ 11: Content and Status将推荐使用lambdas而不是std::bind。在c++ 11中,您可以简单地这样做:
template <typename T>
explicit X(T t)
{
auto f = [t, this]() { this->invoke(t); };
f();
}
// ...
X x([&y](){ y.foo(); });
问题的根本原因似乎是std::bind
对其参数的内部复制,特别是对t
的引用。
你可以这样处理:
template <typename T>
explicit X(T t)
{
std::bind(&X::invoke<T>, this, std::placeholders::_1)(t);
// ^^^^^^^^^^^^^^^^^^^^^ ^
}
这也可以,但不允许使bind
的结果比参数t
的时间长(否则,您将向invoke<T>()
传递一个悬空引用):
template <typename T>
explicit X(T t)
{
std::bind(&X::invoke<T>, this, cref(t))();
// ^^^^^^^
}
更新:
上面的解决方案是可以帮助您实现示例中所显示的内容的变通方法。然而,从评论中可以看出,您的用例可能会有很大的不同(例如,将bind
的结果传递给以后的评估)。
正如Maxim Yegorushkin在他的回答中正确指出的那样,概念上正确的解决方案包括使用Boost的protect
这样的结构。
如果你不想使用Boost,使用c++ 11的可变模板来定义你自己的protect()
函数是很容易的:
// Imitates boost::protect, but with variadic templates and perfect forwarding
namespace detail
{
template<typename F>
struct protect
{
private:
F _f;
public:
explicit protect(F f): _f(f)
{
}
template<typename... Ts>
auto operator () (Ts&&... args) ->
decltype(_f(std::forward<Ts>(args)...))
{
return _f(std::forward<Ts>(args)...);
}
};
}
template<typename F>
detail::protect<F> protect(F&& f)
{
return detail::protect<F>(std::forward<F>(f));
}
最终,这是你在课堂上如何使用它,正如Maxim建议的:
class X
{
public:
template <typename T>
explicit X(T t)
{
auto pt = protect(t);
std::bind(&X::invoke<decltype(pt)>, this, pt)();
}
private:
template <typename T>
void invoke(T t)
{
t();
}
};
- c++\CLI dll包装器,用于调用c++类中的虚拟成员
- C++,当函子不是一个选项时,我如何编写带有自定义函数调用的模板化 RAII 包装器?
- C 函数调用包装器包含类成员功能作为模板参数
- 尝试构造包装器测量函数调用时间时出现问题
- 使用带有 MEX 包装器的帮助程序 C 文件从 MATLAB 2016 调用C++代码时出现问题
- 模板化类包装成员函数调用的行为
- 带有默认参数的宏包装函数调用
- AccessViolationException从托管C (ASP.NET的包装器)调用本机C 代码
- 如何在 C++14 中编写用于调用 Fortran 函数的通用包装器(按引用调用 --按值调用>)
- 包装标准::线程调用函数
- 在没有包装程序类的情况下,在ActiveX接口上调用方法
- 如何检测处理程序是否是 ASIO 链包装并通过链调用它?
- C# 使用包装类中的字符串参数调用 C++ 方法
- 运行并发的CUDA内核,从C 包装器功能调用
- 使用SWIG包装C 类,该类调用另一个对象成员函数
- 包装函数只有在链接为静态时才从链接库调用
- 返回一个 std::函数包装的 lambda,该 lambda 调用指向成员函数的指定指针
- 从包装器调用导出C++ C 函数时LNK2028错误
- 用SWIG包装对象从C++调用Python函数的最干净方法是什么
- 如何用try/catch块包装调用