I'm at a loss as to how to explain why it is valid to create the member inner
in the class template OuterTempl<T>
whereas it is illegal to do so in the untemplated class Outer
.
// Non-template version
struct Outer
{
struct Inner;
Inner inner; // incomplete type (I get this)
};
struct Outer::Inner
{
};
// Template version
template<typename T>
struct OuterTempl
{
struct InnerTempl;
InnerTempl inner; // OK ... Huh!?
};
template<typename T>
struct OuterTempl<T>::InnerTempl
{
};
int main()
{
}
See also ideone.
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.
The member types need to be defined when the class is defined. However, a class template doesn't get defined until it gets instantiated. Any kind of dependent types can change till then. The definition of members is only needed when the class gets instantiated.
On the other hand the definition of a non-template class is a definition which needs to know the size of its member at that point.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With