3

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 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++?

zyndor
  • 1,418
  • 3
  • 20
  • 36

2 Answers2

1

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.

Mark B
  • 95,107
  • 10
  • 109
  • 188
  • Thanks for the point on naming standards - does that only apply to type names? – zyndor Jul 15 '11 at 15:32
  • ...and thanks for the suggestion; tried it now - didn't work. I have now modified the question to better reflect the original problem. (Tested the suggestion with both snippets.) – zyndor Jul 15 '11 at 15:53
1

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;
    ....
Ise Wisteria
  • 11,259
  • 2
  • 43
  • 26