[35.18] Why am I getting errors when my template-derived-class uses a nested type it inherits from its template-base-class?
Perhaps surprisingly, the following code is not valid C++, even though some compilers accept it:
01
template<typenameT>
02
classB {
03
public:
04
classXyz { ... }; // type nested in class B<T>
05
typedefintPqr; // type nested in class B<T>
06
};
07
template<typenameT>
08
classD : publicB<T> {
09
public:
10
voidg()
11
{
12
Xyz x; // bad (even though some compilers erroneously (temporarily?) accept it)
13
Pqr y; // bad (even though some compilers erroneously (temporarily?) accept it)
14
}
15
};
This might hurt your head; better if you sit down.
Within D<T>::g(), name Xyz and Pqr do not depend on template parameter T, so they are known as a nondependent names.
On the other hand, B<T> is dependent on template parameter T so B<T> is called a dependent name.
Here’s the rule: the compiler does not look in dependent base classes (like B<T>) when looking up nondependent names (like Xyz or Pqr). As a result, the compiler does not know they even exist let alone are types.
At this point, programmers sometimes prefix them with B<T>::, such as:
1
template<typenameT>
2
classD : publicB<T> {
3
public:
4
voidg()
5
{
6
B<T>::Xyz x; // bad (even though some compilers erroneously (temporarily?) accept it)
7
B<T>::Pqr y; // bad (even though some compilers erroneously (temporarily?) accept it)
8
}
9
};
Unfortunately this doesn’t work either because those names (are you ready? are you sitting down?) are not necessarily types.
“Huh?!?” you say.
“Not types?!?” you exclaim.
“That’s crazy; any fool can SEE they are types; just look!!!” you protest.
Sorry, the fact is that they might not be types. The reason is that there can be a specialization of B<T>, say B<Foo>, where B<Foo>::Xyz is a data member, for example. Because of this potential specialization, the compiler cannot assume that B<T>::Xyz is a type until it knows T.
The solution is to give the compiler a hint via the typename keyword: