Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::function bound to member function

The following code doesn't compile in VS2012

class Zot
{
public:
    int A() { return 123; }
};

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

However, changing the assignment to

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

Does work.

There are a lot of online examples that show the original syntax. Did something change in the C++11 spec to disallow this syntax?

Is there a valid shorter form for the assignment?

Edit: the compiler error (slightly edited for reabability) is:

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>          ]
like image 813
Rob Walker Avatar asked Aug 27 '12 15:08

Rob Walker


2 Answers

The following syntax works and is shorter at least:

std::function<int (Zot*)> fn = std::mem_fn(&Zot::A);
like image 71
Rob Walker Avatar answered Sep 30 '22 12:09

Rob Walker


Yes, it should work. One of the requirements on the functor argument for any of the appropriate constructor (e.g. template<class F> function(F f);) of std::function<R(ArgsTypes...)> is:

f shall be Callable (20.8.11.2) for argument types ArgTypes and return type R.

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

In turn, "Callable for argument types ArgTypes and return type R" is a Standard quasi-concept (for lack of concepts) defined in terms of the pseudo-expression INVOKE(f, declval<ArgTypes>()..., R). This pseudo-expression unifies regular functors, which are invoked with the usual call syntax (e.g. f(a, b, c)), with pointers to members which have their own quirks (e.g. p->*a or (r.*a)(b, c)). INVOKE is defined in 20.8.2 Requirements [func.require].

Furthermore, the effects of using the call operator of std::function include INVOKE(f, std::forward<ArgTypes>(args)..., R) (20.8.11.2.4 function invocation [func.wrap.func.inv]), meaning that the 'right' thing is done for pointers to members.

There are in fact a lot of other things that are also defined in terms of Callable/INVOKE in the Standard, like std::bind, std::thread, std::reference_wrapper and std::result_of*.

*: in particular this means that something like

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

is problematic at least for that reason.

like image 36
Luc Danton Avatar answered Sep 30 '22 13:09

Luc Danton