使用枚举作为常量表达式。哪个编译器是正确的?

问题描述:

以下代码使用枚举成员m作为常量表达式,即作为模板参数。代码在gcc下编译,但不在clang下(live demo)。铿锵说:“错误:非类型模板参数不是一个常量表达式”。使用枚举作为常量表达式。哪个编译器是正确的?

该问题可以通过A<tst<p>::m> a交换// 1来解决。因此,我的问题不是如何解决这个问题,而是哪个编译器是正确的。

template<size_t n> struct A{}; 

template<size_t n> 
struct tst 
{ enum : size_t { m= n % 15 }; 

    template<size_t p> 
    void 
    call(tst<p> const &t2) { 
     A<t2.m> a; // 1 
    } 
}; 
+0

[This references says](http://en.cppreference.com/w/cpp/language/enum)“当非范型枚举是类成员时,它的枚举器可以使用类成员访问运算符'.'来访问。和' - >'“。它没有提到任何关于常量表达的内容。 –

+1

@JoachimPileborg标准的§7.2.2'确实说' 枚举器列表中的标识符被声明为常量,并且可以出现在需要常量的地方。' – lcs

根据该标准,Clang有权拒绝该代码。

t2.m是一个类成员访问表达式。 [expr.ref]/1说:

[...] The postfix expression before the dot or arrow is evaluated; the result of that evaluation, together with the id-expression, determines the result of the entire postfix expression.

还有一张纸条:

If the class member access expression is evaluated, the subexpression evaluation happens even if the result is unnecessary to determine the value of the entire postfix expression, for example if the id-expression denotes a static member.

所以,子表达式t2进行评估。 [expr.const] /2.9说,表达e不能是核心常量表达式如果计算它在

an id-expression that refers to a variable or data member of reference type unless the reference has a preceding initialization and either

  • it is initialized with a constant expression or
  • its lifetime began within the evaluation of e ;

t2的评价结果​​是指参考类型的变量不满足子弹,所以t2.m不是一个常量表达式,因为它不是一个核心常量表达式。


来自N4594的所有报价是当前发布的工作草案。自C++ 11以来,文本发生了轻微的变化,但这种情况下的含义是相同的。

+0

Thx。有没有人提交gcc的错误报告? –

+0

@ClaasBontus我没有。通过错误数据库的搜索将是有序的,但到目前为止我还没有时间做到这一点。 – bogdan

+0

可能[Bug 39970](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39970)。 –