std::function绑定到成员函数

7
以下代码在VS2012中无法编译。
class Zot
{
public:
    int A() { return 123; }
};

int _tmain(int argc, _TCHAR* argv[])
{
    std::function<int (Zot*)> fn = &Zot::A;
    return 0;
}

然而,将任务分配更改为

    std::function<int (Zot*)> fn = std::bind(&Zot::A, std::placeholders::_1);

可以工作。

有很多在线示例展示原始语法,C++11规范中有什么变化导致不允许使用这种语法吗?

是否有有效的更短形式的赋值方法?

编辑:编译器错误(稍作修改以提高可读性):

1>vc\include\functional(515): error C2664: 'std::_Func_class<_Ret,_V0_t>::_Set' : cannot convert parameter 1 from '_Myimpl *' to 'std::_Func_base<_Rx,_V0_t> *'
1>          with
1>          [
1>              _Ret=int,
1>              _V0_t=Zot *
1>          ]
1>          and
1>          [
1>              _Rx=int,
1>              _V0_t=Zot *
1>          ]
1>          Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
1>          vc\include\functional(515) : see reference to function template instantiation 'void std::_Func_class<_Ret,_V0_t>::_Do_alloc<_Myimpl,_Fret(__thiscall Zot::* const &)(void),_Alloc>(_Fty,_Alloc)' being compiled
1>          with
1>          [
1>              _Ret=int,
1>              _V0_t=Zot *,
1>              _Fret=int,
1>              _Alloc=std::allocator<std::_Func_class<int,Zot *>>,
1>              _Fty=int (__thiscall Zot::* const &)(void)
1>          ]
1>          vc\include\functional(515) : see reference to function template instantiation 'void std::_Func_class<_Ret,_V0_t>::_Do_alloc<_Myimpl,_Fret(__thiscall Zot::* const &)(void),_Alloc>(_Fty,_Alloc)' being compiled
1>          with
1>          [
1>              _Ret=int,
1>              _V0_t=Zot *,
1>              _Fret=int,
1>              _Alloc=std::allocator<std::_Func_class<int,Zot *>>,
1>              _Fty=int (__thiscall Zot::* const &)(void)
1>          ]
1>          vc\include\functional(515) : see reference to function template instantiation 'void std::_Func_class<_Ret,_V0_t>::_Reset_alloc<_Fret,Zot,std::allocator<_Ty>>(_Fret (__thiscall Zot::* const )(void),_Alloc)' being compiled
1>          with
1>          [
1>              _Ret=int,
1>              _V0_t=Zot *,
1>              _Fret=int,
1>              _Ty=std::_Func_class<int,Zot *>,
1>              _Alloc=std::allocator<std::_Func_class<int,Zot *>>
1>          ]
1>          vc\include\functional(515) : see reference to function template instantiation 'void std::_Func_class<_Ret,_V0_t>::_Reset_alloc<_Fret,Zot,std::allocator<_Ty>>(_Fret (__thiscall Zot::* const )(void),_Alloc)' being compiled
1>          with
1>          [
1>              _Ret=int,
1>              _V0_t=Zot *,
1>              _Fret=int,
1>              _Ty=std::_Func_class<int,Zot *>,
1>              _Alloc=std::allocator<std::_Func_class<int,Zot *>>
1>          ]
1>          vc\include\functional(675) : see reference to function template instantiation 'void std::_Func_class<_Ret,_V0_t>::_Reset<int,Zot>(_Fret (__thiscall Zot::* const )(void))' being compiled
1>          with
1>          [
1>              _Ret=int,
1>              _V0_t=Zot *,
1>              _Fret=int
1>          ]
1>          vc\include\functional(675) : see reference to function template instantiation 'void std::_Func_class<_Ret,_V0_t>::_Reset<int,Zot>(_Fret (__thiscall Zot::* const )(void))' being compiled
1>          with
1>          [
1>              _Ret=int,
1>              _V0_t=Zot *,
1>              _Fret=int
1>          ]
1>          c:\..\cxx11.cpp(17) : see reference to function template instantiation 'std::function<_Fty>::function<int(__thiscall Zot::* )(void)>(_Fx &&)' being compiled
1>          with
1>          [
1>              _Fty=int (Zot *),
1>              _Fx=int (__thiscall Zot::* )(void)
1>          ]
1>          c:\...\cxx11.cpp(17) : see reference to function template instantiation 'std::function<_Fty>::function<int(__thiscall Zot::* )(void)>(_Fx &&)' being compiled
1>          with
1>          [
1>              _Fty=int (Zot *),
1>              _Fx=int (__thiscall Zot::* )(void)
1>          ]

2
在VS2010和GCC 4.7.1上编译并运行正常。 - Praetorian
Luc Danton的分析听起来很有道理:这似乎可能是一个错误,至少需要进一步调查。如果可以的话,请在[Microsoft Connect](http://connect.microsoft.com/VisualStudio)上打开一个错误,并在此处发布链接,以便其他人可以找到它。同时,我建议使用`std :: mem_fn`作为解决方法。 - James McNellis
1
谢谢 - 我已将错误报告提交为:https://connect.microsoft.com/VisualStudio/feedback/details/759806/cant-assign-std-function-with-member-function - Rob Walker
2个回答

5
以下语法可以正常工作,至少更简洁:
std::function<int (Zot*)> fn = std::mem_fn(&Zot::A);

为什么 std::mem_fn(&Zot::A) 能够工作而 &Zot::A 不能?请解释。 - Narek

2
是的,它应该可以工作。对于std::function<R(ArgsTypes...)>的任何适当构造函数(例如template<class F> function(F f);),functor参数的一个要求是:

f应为Callable (20.8.11.2),其参数类型为ArgTypes,返回类型为R

(20.8.11.2.1 functionconstruct/copy/destroy [func.wrap.func.con])

进一步地,“对于参数类型为ArgTypes和返回类型为RCallable”是一个标准的伪概念(由于缺乏概念而定义),其定义基于伪表达式INVOKE(f, declval<ArgTypes>()..., R)。这个伪表达式将常规函数对象(使用通常的调用语法调用,例如f(a, b, c))与具有自己怪癖的成员指针(例如p->*a(r.*a)(b, c))统一起来。 INVOKE在20.8.2 Requirements [func.require]中定义。

此外,使用std::function的调用运算符的影响包括INVOKE(f, std::forward<ArgTypes>(args)..., R)(20.8.11.2.4 function invocation [func.wrap.func.inv]),这意味着针对成员指针做了正确的事情。

实际上,标准中还有很多其他东西也是基于Callable/INVOKE定义的,例如std::bindstd::threadstd::reference_wrapperstd::result_of*。

*:特别是这意味着像下面这样的东西:

template<typename Functor>
typename std::result_of<Functor()>::type apply(Functor functor)
{ return std::forward<Functor>(functor)(); }

至少出于这个原因,IT技术是有问题的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接