Yes - consider [temp.mem.class]/1:
A member class of a class template may be defined outside the class
template definition in which it is declared.
[ Note: The member
class must be defined before its first use that requires an
instantiation (14.7.1). For example,
template<class T> struct A {
class B;
};
A<int>::B* b1; // OK: requires A to be defined but not A::B
template<class T> class A<T>::B { };
A<int>::B b2; // OK: requires A::B to be defined
— end note ]
It is also important to mention that the definition of inner
, which constitutes the use of Inner
the above note describes, is only instantiated once it is required:
Unless a member […] has been explicitly instantiated or explicitly specialized, the specialization
of the member is implicitly instantiated when the specialization is
referenced in a context that requires the member definition to exist;
Since no instantiation of OuterTempl
is present in your code, the definition of inner
is never instantiated, and an instantiation of Inner
is never necessitated. The completeness of the nested class type for such a declaration is thus only required at the point of instantiation. You don't instantiate OuterTempl
here, but if you would do that before the definition of Inner
, the code would be ill-formed.
That is,
template<typename T>
struct OuterTempl
{
struct InnerTempl;
InnerTempl inner;
};
template struct OuterTempl<int>; // Bad - Ill-formed (NDR?)
template<typename T>
struct OuterTempl<T>::InnerTempl {};
template struct OuterTempl<int>; // Fine
Demo.