【发布时间】:2014-10-10 16:30:34
【问题描述】:
我有以下示例,我从§14.7.3/6 [temp.expl.spec] 分解而来,它在主模板中定义了一个类成员枚举并随后对其进行了专门化。以下内容无法在 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
原因应该是在特化之前实例化了无作用域成员枚举的定义。 14.7.1 [temp.inst]/1:
类模板特化的隐式实例化导致 [...] 无范围成员枚举和成员匿名联合的定义的隐式实例化。
我试图理解为什么这是一个问题。是不是因为如果枚举已经有了定义,那么在特化过程中会导致重定义错误?
【问题讨论】:
-
在您引用的示例之前的段落中,它说“如果一个模板、一个成员模板或一个类模板的成员是明确专门化的,那么该专门化应在第一次使用之前声明会导致隐式实例化发生的专门化,在发生这种使用的每个翻译单元中;不需要诊断。"
-
这为我编译,并提供了预期的专业化。 (g++ 4.8.2)@T.C.我真的不明白这将如何应用在这里。
-
@T.C.我已经读了好几遍了。它需要的声明是什么样的?
-
Clang++ 使用 scoped 枚举来编译它。由于他们的定义似乎没有被实例化,我认为这是合规且格式良好的。上述规则要么来自 C++03,其中前向声明枚举是不可能的,要么这可能与名称查找有关(未作用域的枚举 => 名称被注入到类作用域中)。 (关于匿名工会的部分向我暗示这与名称查找有关。)
-
[basic.lookup.qual]/1 "在
::作用域解析运算符应用于nested-name-之后,可以引用类或命名空间成员或枚举器的名称-表示其类、命名空间或枚举的说明符。”所以一般规则是对于A<int>::@,可以找到一个无范围的枚举成员作为名称@。通常,这意味着必须实例化枚举。可能,您可以在定义enum期间添加一个特殊的名称查找规则。
标签: c++ templates c++11 enums template-specialization