Как вывести тип класса из типа метода в шаблонах C ++? - PullRequest
2 голосов
/ 30 сентября 2010

В шаблонах, как показано ниже, я бы хотел, чтобы вызов Run(&Base::foo) выполнялся без необходимости называть базовый тип дважды (как это делается при вызове Run<Base>(&Base::foo) при компиляции).Могу ли я иметь это?Возможно, без добавления тонны Boost заголовков?

С предоставленным кодом я получаю ошибку:

prog.cpp:26: error: no matching function for call to ‘Run(bool (Base::*)())’

(вы можете поиграть с фрагментом в http://ideone.com/8NZkq):

#include <iostream>

class Base {
public:
  bool foo() { return true; }
};

Base* x;

template<typename T>
struct Traits {
  typedef bool (T::*BoolMethodPtr)();
};

template<typename T>
void Run(typename Traits<T>::BoolMethodPtr check) {
  T* y = dynamic_cast<T*>(x);
  std::cout << (y->*check)();
}

int main() {
  Base y;
  x = &y;
  Run<Base>(&Base::foo);
  Run(&Base::foo); // why error?
}

Ответы [ 4 ]

10 голосов
/ 30 сентября 2010

T в Traits<T>::BoolMethodPtr находится в невыбранном контексте, поэтому компилятор не будет автоматически определять из вызова тип T.Это потому, что может быть такой код:

template<typename T>
struct Traits {
  typedef bool (T::*BoolMethodPtr)();
};

template<>
struct Traits<int> {
  typedef bool (Base::*BoolMethodPtr)();
};

Run(&Base::foo); /* What should T be deduced to? Base and int are both equally possible */

Если вы можете обойтись без класса Traits<T>, вы можете написать Run как:

template<class Class>
void Run(bool (Class::*check)()) {
  Class* y = dynamic_cast<Class*>(x);
  std::cout << (y->*check)();
}

В этом контекстеClass можно вывести как среднее Base

4 голосов
/ 30 сентября 2010

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

template< typename T >
struct get_host_class; // most types are not ptmfs: don't implement this

template< typename C >
struct get_host_class< bool (C::*)() > { // implement partial specialization
     typedef C host;
     typedef void sfinae; // disallow function for non ptmf arguments
};

template< typename T >
typename get_host_class<T>::sfinae Run( T check) {
    typedef T BoolMethodPtr; // or something
    typedef typename get_host_class< T >::host host;
}
2 голосов
/ 30 сентября 2010

Когда компилятор пытается сопоставить аргумент шаблона, он учитывает только основной тип класса. Другими словами, когда встречается выражение:

Run(&Base::foo);

... и он пытается определить параметр шаблона для Run, он учитывает только сам тип foo и не учитывает, какой класс foo является частью.

EDIT:

И тип foo равен bool(Base::*)(void), но компилятор должен найти только Base

2 голосов
/ 30 сентября 2010

Я думаю, что это не выводимый контекст.

$ 14.8.2.5 / 5- "Не выведенные контексты: - Спецификатор вложенного имени типа, который был указан с использованиемqualid-id. "

Я думаю, что это цитата, которая применяется в этом случае.Но некоторые шаблонные боги должны утвердить мое понимание.

...