Question

1 #include <iostream>
2 using namespace std;
3 template<typename T>
4 class Top {
5 public:
6     class Sub {
7         protected:
8             T age;
9     };
10     class Derived : public Sub {
11         public:
12             void printAge() {
13                 cout << age << endl;
14             }
15     };  
16 };
17 int main()
18 {
19     return 0;
20 }

when I complie the codes, I get the following errors:

test.cpp: In member function ‘void Top<T>::Derived::printAge()’:
test.cpp:13:25: error: ‘age’ was not declared in this scope
             cout << age << endl;

But if it's not a template, it will be ok. I'm glad to receive your answers.

Was it helpful?

Solution

age in Derived is name inside a template. There are 2 kind of name defined by the standard:

  • Dependent : names that depend on the template parameters but aren’t declared within the template.
  • Non dependent : names that don’t depend on the template parameters, plus the name of the template itself and names declared within it.

At the line cout << age << endl, age is a Non dependent name that shall be resolved at the point of the template’s definition. At that point, the compiler still doesn’t know what age is, because Top::sub could be/can be specialized later. So it doesn’t look names up in the base class, but only in the enclosing scope. Since there’s no age in the enclosing scope, the compiler complains.

Adding this-> or Top:: on age makes it dependent, hence the lookup rule changes. Now age is resolved at the point of the template’s instantiation, where the compiler has full understanding of the base class and can resolve the name correctly.

OTHER TIPS

class Top<T>::Derived : public Top<T>::Sub

is another way to think of Derived s inheritance. If thought of this way, then variables from Sub appear to be dependent on the type T. When you use variables dependent on the template parameter type you often need to be either explicit (Sub::age) or make it clear it is a member (this->age).

Now in this case, while it appears that base is dependent on T, you can prove what is in base. However this will end up depending on some fine wording in the standard, and the compiler's implementation of that corner case (either successful or not).

So to fix your problem, use this->age in that situation.

age depends on a template type parameter, so its evaluation is to the template instantation phase. As you can see in this thread, inheritance and templates don't work very well. The use of a member on the derived class is checked at the first (declaration) phase, and (as I said above), the memeber is declared ("parsed") at the second phase. So the compiler things that the memeber was not declared.

One way to solve that is to access the memeber through this pointer, to force the compiler to check the base class.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top