Частичная специализация шаблона функтора, вызывающего метод-член переданных ему объектов - PullRequest
3 голосов
/ 15 июля 2011

У меня есть следующий функтор и его частичная специализация

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;
};

Я пытаюсь использовать его следующим образом:

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));

Я получаю это, для последней строки кода (IDE поднимается у вызывающей стороны):

ошибка C2440: '': невозможно преобразовать из 'void (__thiscall Foo :: *) (void) const 'to' Caller <_T> ' 1> с 1> [ 1> _T = const Foo 1>] 1> Ни один конструктор не может принять тип источника или перегрузку конструктора разрешение было неоднозначным

Этот код будет работать в среде g ++. (Если бы я Caller<Foo>(&Foo::Bar) g ++ пожаловался, что имеет смысл, так как функция будет вызываться только для const объекта).

Я пробовал разные вещи, включая добавление operator()(const _T& obj) / operator()(const _T& obj) const разновидностей к функтору, но безрезультатно.

Это будет принято компилятором:

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));

Что я делаю не так? Как заставить шаблон функтора работать для константных функций-членов в Visual C ++?

Ответы [ 2 ]

1 голос
/ 15 июля 2011

Я думаю, что константа _T в Caller не отражается в константе this в Method автоматически в MSVC (во всяком случае, я считаю, что поведение GCC, о котором вы упоминали, странное).
Если вы хотите отразить постоянство _T в постоянстве this, как насчет подготовки вспомогательного класса Select_Type, как показано ниже, и выбора правильной подписи в соответствии с константой 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;
    ....
1 голос
/ 15 июля 2011

Ваши operator() функции должны быть константными (они не изменяют сам функтор, но я не верю, что вам нужен новый набор функций).

Также обратите внимание, что все ваши типы, начинающиеся с подчеркивания и заглавной буквы, зарезервированы стандартом для реализации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...