Consider the following:
template<typename X>
struct Z {};
struct A
{
using Z = ::Z<int>;
struct B : Z
{
using C = Z;
};
};
This compiles fine. Nice. But now add another parameter in Z:
template<typename X, typename Y>
struct Z {};
struct A
{
template<typename X>
using Z = ::Z<X, int>;
struct B : Z<B>
{
using C = Z<B>; // error: too few template arguments for class template 'Z'
};
};
Ok, maybe it makes sense that the definition of template alias Z in class A is visible when deriving nested class B, but not inside its body, triggering the error since the global definition of Z has two parameters.
But why is the behavior different in the first case, when Z is just a type alias in A?
Finally, make A a template:
template<typename X, typename Y>
struct Z {};
template<typename T>
struct A
{
template<typename X>
using Z = ::Z<X, int>;
struct B : Z<B>
{
using C = Z<B>;
};
};
Now the error is gone. Why?
(Tested on Clang 3.6 and GCC 4.9.2)
In short: Deriving from a specialization of
Zintroduces the injected-class-name of::Z, which is found before the alias template. IfAis a template, however, the injected-class-name is not found anymore because the base class ofBis dependent.Consider [temp.local]/1:
And [basic.lookup]/3:
Zis looked up as an unqualified name; [basic.lookup.unqual]/7:Thus, the injected-class-name
Zis found as a member of the base classZ<B, int>, and used as a template-name, which renders your second program ill-formed. In fact, your first snippet uses the injected-class-name as well - the following snippet won't compile:Finally, if
Ais made a template, note thatBis a dependent type as per [temp.dep.type]/(9.3)1, thusZ<B>is a dependent type as per [temp.dep.type]/(9.7), thus the base classZ<B>is not examined during lookup for the unqualified-idZaccording to [temp.dep]/3:Hence the injected-class-name won't be found.
1
Bis a "nested class [..] that is a dependent member of the current instantiation" (emphasis mine), since