Как использовать typedef из базового класса шаблона в Ctor of the Derived? - PullRequest
0 голосов
/ 09 октября 2018

Если у меня есть базовый и производный класс, которые оба шаблона :

template <typename T>
class Base {
public:
    typedef T (*func)();
    Base(func f):m_f(f){};
    T invoke(){ return m_f();};
private:
    func m_f;
};

template <typename D>
class Derived : public Base<D> {
public:
    Derived(Base<D>::func f) : Base<D>(f) { };
    D foo() {
        return Base<D>::invoke();
    }
};

Производный класс должен передать указатель функции на базу в Ctor.После прочтения Наследование и шаблоны в C ++ - почему методы невидимы? Я понимаю, что typedef в Ctor должен вызываться следующим образом:

Derived(Base<D>::func f) : Base<D>(f) {};

Но потом, когда я пытаюсьдля компиляции:

int returnZero(){
    return 0;
}

Derived<int> d(returnZero);
std::cout << d.foo() << std::endl;

Я получаю:

  error: expected ')' before 'f'
  Derived(Base<D>::func f) : Base<D>(f) { };
                        ^
cpp_code.cpp: In function 'int main()':
cpp_code.cpp:59:27: error: no matching function for call to 'Derived<int>::Derived(int (&)())'
  Derived<int> d(returnZero);
                           ^
cpp_code.cpp:47:7: note: candidate: constexpr Derived<int>::Derived(const Derived<int>&)
 class Derived : public Base<D> {
       ^~~~~~~
cpp_code.cpp:47:7: note:   no known conversion for argument 1 from 'int()' to 'const Derived<int>&'
cpp_code.cpp:47:7: note: candidate: constexpr Derived<int>::Derived(Derived<int>&&)
cpp_code.cpp:47:7: note:   no known conversion for argument 1 from 'int()' to 'Derived<int>&&'

Как правильно использовать указатель функции (func) в Ctor?

1 Ответ

0 голосов
/ 09 октября 2018

Clang как обычно выдает очень полезное сообщение об ошибке, которое объясняет все:

error: missing 'typename' prior to dependent type name 'Base<D>::func'
    Derived(Base<D>::func f) : Base<D>(f) { };
            ^~~~~~~~~~~~~
            typename 

Если зависимое имя является типом или шаблоном, оно должно быть устранено с помощью ключевого слова typename или template соответственно.

Это необходимо, потому что в определении Derived компилятор не знает, какой тип будет использоваться вместо D, и поэтому он не знает, каково будет фактическое определение Base<D>из-за возможных специализаций.Вот почему любой идентификатор внутри Base<D> зависит от типа D.

Однако компилятору все еще нужно иметь возможность анализировать этот код, который он понимает лишь частично, поэтомувам нужно помочь, сказав, что идентификатор func является не просто членом Base<D>, но typename, поскольку он определяет контекст, в котором этот идентификатор может использоваться.


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