Partial template specialisation of a functor that's calling a member method of objects passed to it
I have the following functor and its partial specialisation
template <class _T, typename _Return = void, typename _Arg = void>
struct Caller
{
typedef _Return(_T::*Method)(_Arg);
Caller(Method pm, _Arg a)
: _pMethod(pm),
_arg(a)
{}
_Return operator()(_T& obj)
{
return (obj.*_pMethod)(_arg);
}
Method _pMethod;
_Arg _arg;
};
template <class _T, typename _Return>
struct Caller<_T, _Return, void>
{
typedef _Return(_T::*Method)();
Caller(Method pm)
: _pMethod(pm)
{}
_Return operator()(_T& obj)
{
return (obj.*_pMethod)();
}
Method _pMethod;
};
I'm trying to use it the following way:
struct Foo
{
void Bar() const
{
void(0);
}
};
// ...
std::list<Foo> foos;
const std::list<Foo> &rFoos(foos);
std::for_each(rFoos.begin(), rFoos.end(), Caller<const Foo>(&Foo::Bar));
I'm getting this, for the last line of code (the IDE picks up at the Caller):
error C2440: '' : cannot convert from 'void (__thiscall Foo::* )(void) const' to 'Caller<_T>' 1> with 1> [ 1> _T=const Foo 1> ] 1> No constructor could take the source type, or constructor overload resolution was ambiguous
This code would work in a g++ environment. (If I Caller<Foo>(&Foo::Bar)
g++ would complain, which makes sense, as the function will only be called on a const object).
I have tried various things, including adding operator()(const _T& obj)
/ operator()(const _T& obj) const
varieties to the functor, but to no avail.
This would开发者_Python百科 be accepted by the compiler:
struct Foo
{
void Bar()
{
void(0);
}
};
// ...
std::list<Foo> foos;
const std::list<Foo> &rFoos(foos);
std::for_each(rFoos.begin(), rFoos.end(), Caller<Foo>(&Foo::Bar));
What am I doing wrong? How can I make the functor template work for const member functions in Visual C++?
I think the constness of _T
in Caller
doesn't reflect in this
's
constness of Method
automatically in MSVC
(If anything, I feel GCC's behaviour you mentioned is strange).
If you want to reflect the constness of _T
in the constness of this
,
how about preparing auxiliary class Select_Type
like the following, and
selecting the proper signature according to the constness of T_
?
template <class C, class T, class Const_T>
struct Select_Type { typedef T type; };
template <class C, class T, class Const_T>
struct Select_Type<C const, T, Const_T> { typedef Const_T type; };
template <class _T, typename _Return>
struct Caller<_T, _Return, void>
{
typedef typename Select_Type<
_T, _Return(_T::*)(), _Return(_T::*)()const >::type Method;
....
Your operator()
functions need to be const (they don't mutate the functor itself, but I don't believe you need a new set of functions).
Also note that all your types that start with underscore and a capital letter are reserved by the standard for the implementation.
精彩评论