When instantiating a template, should members of its incomplete argument types be visible?
Solution 1:
Whether typename T::Before
is valid is not explicitly said by the spec. It is subject of a defect report (because the Standard can very reasonably be read to forbid it): http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#287 .
Whether typename T::After
is invalid can also very reasonably be read to be true by the spec, and actually it makes quite a bit of sense (and aforementioned DR still keeps it ill-formed). Because you have an instantiation of a class A<Foo>
, which references another class A<Bar>
during a period where a member Baz
has not yet been declared, and that makes a reference back to A<Foo>::Bar
. That is ill-formed in the case of non-templates aswell (try to "forget" for a moment that you are dealing with templates: surely the lookup of B<A>::After
is done after the A
template was completely parsed, but not after the specific instantiation of it was completely created. And it is the instantiation of it that actually will do the reference!).
struct A {
typedef int Foo;
typedef A::Foo Bar; // valid
typedef A::Baz Lulz; // *not* valid
typedef int Baz;
};
Solution 2:
T::Before
and T::After
are dependent names due to [temp.dep.type]/8 and /5.
Dependent names are looked up "at the point of the template instantiation (14.6.4.1) in both the context of the template definition and the context of the point of instantiation." [temp.dep]/1
I interpret this as: They're looked up when the template is instantiated. Where are they looked up? At the context of the template definition and the context of the point of instantiation.
[temp.dep.type]/7 On the other hand states:
If, for a given set of template arguments, a specialization of a template is instantiated that refers to a member of the current instantiation with a qualified-id or class member access expression, the name in the qualified-id or class member access expression is looked up in the template instantiation context.
[temp.point]/7 Defines the instantiation context as follows:
The instantiation context of an expression that depends on the template arguments is the set of declarations with external linkage declared prior to the point of instantiation of the template specialization in the same translation unit.
Therefore, we need to know what the point of instantiation is.
[temp.point]/4
For a class template specialization [...], if the specialization is implicitly instantiated because it is referenced from within another template specialization, if the context from which the specialization is referenced depends on a template parameter, and if the specialization is not instantiated previous to the instantiation of the enclosing template, the point of instantiation is immediately before the point of instantiation of the enclosing template.
Although the injected class name Correction by Johannes Schaub: It is a dependent name. See [temp.local]/1 and [temp.dep.type]/8 => A
is arguably a context that depends (as a layman term) on the template parameters of A
, the name A
itself is not a dependent name.A
is a dependent type.
Therefore, this condition is not fulfilled, and B<A>
should be instantiated before A<int>
.