0

If I have a base and a derived class which are both templates:

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

The derived class needs to pass a function pointer to the base in the Ctor. After reading Inheritance and templates in C++ - why are methods invisible? I understand that the typedef in the Ctor should be called in the following manner:

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

But then, when I try to compile:

int returnZero(){
    return 0;
}

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

I get:

  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>&&'

What would be the proper way to use the function pointer (func) in the Ctor?

user3698979
  • 103
  • 1
  • 9

1 Answers1

3

Clang as usually gives a very useful error message that explains everything:

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

If a dependent name is a type or template it should be disambiguated with a typename or a template keyword respectively.

This is needed because in the Derived definition the compiler doesn't know what type would be used instead of D and therefore it doesn't know what would be the actual definition of Base<D> due to possible specializations. That's why any identifier inside Base<D> is dependent on type D.

The compiler, however, still needs to be able to parse this code that it only partially understands, that's why you need to help it by telling that the identifier func is not just a member of Base<D>, but a typename, since that defines the context in which this identifier can be used.


On a side note: there is a proposal to get rid of this annoying rule for the contexts where nothing but type can be used, such as yours.
r3mus n0x
  • 5,954
  • 1
  • 13
  • 34