简体   繁体   中英

Dynamic initialization of enum class inside template struct

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 (ie, 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; }; template<typename T> struct X { T obj; }; work?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM