15
votes

I have the following example that I've decomposed from §14.7.3/6 [temp.expl.spec] that defines a class member enumeration in the primary template and subsequently specializes it. The following doesn't compile in clang:

template<class T>
struct A {
    enum E : T;
};

template<class T>
enum A<T>::E : T { eT };

template<>
enum A<char>::E : char { echar }; // ill-formed, A<char>::E was instantiated
                                  // when A<char> was instantiated

// error: explicit specialization of 'E' after instantiation

The reason is supposed to be that the definition of the unscoped member enumeration was instantiated before the specialization. 14.7.1 [temp.inst]/1:

The implicit instantiation of a class template specialization causes the implicit instantiation of [...] the definitions of unscoped member enumerations and member anonymous unions.

I'm trying to understand why that is a problem exactly. Is it because if the enumeration already has a definition, then that would cause a redefinition error during the specialization?

1
In the paragraph right before the example you quoted, it says "If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required."T.C.
This compiles for me, and provides the intended specialization. (g++ 4.8.2) @T.C. I don't really see how that would apply here.Captain Giraffe
@T.C. I've read that several times. What would that declaration that it requires look like?0x499602D2
Clang++ compiles this with a scoped enumeration. Since their definitions don't seem to be instantiated, I think this is compliant and well-formed. Either the above rule comes from C++03, where forward-declaring enums was impossibly, or this might have to do with name lookup (unscoped enum => name is injected into class scope). (The part about anonymous unions suggests to me it has to do with name lookup.)dyp
[basic.lookup.qual]/1 "The name of a class or namespace member or enumerator can be referred to after the :: scope resolution operator applied to a nested-name-specifier that denotes its class, namespace, or enumeration." So the general rule is that for A<int>::@, an unscoped enumeration member can be found as a name @. Typically, this implies that the enumeration has to be instantiated. Possibly, you could add a special rule for name lookup during the definition of an enum.dyp

1 Answers

1
votes

you need to specialize for the whole class definition:

template<class T>
struct A {
  enum E : T { eT };
};

template<>
struct A<char> {
  enum E : char { echar };
};