I was compiling following test code with clang :
template<typename T> struct S1
{
struct S2{
enum class E1;
enum class E2: T;
enum class E3: short;
};
typename S2::E1 b1;
typename S2::E2 b2;
typename S2::E3 b3;
enum class S1::S2::E1 {e11,e12};
enum class S1::S2::E2 : T {e21,e22};
enum class S1::S2::E3 : short {e31,e32};
};
template struct S1<int>;
I got error : template specialization or definition requires a template parameter list corresponding to the nested type 'S1< T >'. My guess is since struct S1 is being defined while adding member in
enum class S1::S2::E1 {e11,e12}
enum class S1::S2::E2 : T {e21,e22};
enum class S1::S2::E3 : short {e31,e32};
the compiler does not know what is T since S1 is not instantiated yet and hence T cannot be resolved. The compiler thus does not know the size for the enum members and hence throws error. Is this correct? Is it specified in standards?
Note : gcc does not throw any such error.
It's simply not allowed to define an enum
like that. Paragraph 7.2/4 in n3337 states:
If the enum-key is followed by a nested-name-specifier, the enum-specifier shall refer to an enumeration that was previously declared directly in the class or namespace to which the nested-name-specifier refers (i.e., neither inherited nor introduced by a using-declaration), and the enum-specifier shall appear in a namespace enclosing the previous declaration.
Granted, the error message is not exactly stellar. Your example can be vastly simplified to this:
template<typename T> struct S1
{
struct S2 {
enum class E;
};
enum class S2::E {};
};
which will produce the same error message.
Valid options are:
// definition in the scope that the declaration appears in
template<typename T> struct S1
{
struct S2 {
enum class E;
enum class E {};
};
};
or
// definition in the enclosing namespace scope
template<typename T> struct S1
{
struct S2 {
enum class E;
};
};
template<typename T>
enum class S1<T>::S2::E {};
The same rule applies also for nested classes (see 9.7/3). If you try this
template<typename T>
struct S1
{
struct S2 {
struct S3;
};
struct S2::S3 {};
};
then GCC, too, produces a (similarly unhelpful) error. That it doesn't do the same with enums appears to be a bug.
And your own explanation you brought up for the error is incorrect. In the definition of a template the compiler doesn't need to (and obviously can't) know what T
is. It only needs it when it instantiates the template. How else would something like template<typename T> struct X { T obj; };
work?