【问题标题】:Using an enum as a constant expression. Which compiler is right?使用枚举作为常量表达式。哪个编译器是对的?
【发布时间】:2016-11-18 19:17:10
【问题描述】:

以下代码使用枚举成员m 作为常量表达式,即作为模板参数。该代码在 gcc 下编译,但不在 clang (live demo) 下编译。 Clang 说“错误:非类型模板参数不是常量表达式”。

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

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
    }
};

【问题讨论】:

  • This references says "当一个无作用域的枚举是类成员时,可以使用类成员访问运算符.-&gt; 访问它的枚举数"。但是它没有提到任何关于常量表达式的内容。
  • @JoachimPileborg 标准§ 7.2.2 确实说The identifiers in an enumerator-list are declared as constants, and can appear wherever constants are required.

标签: c++ c++11


【解决方案1】:

根据标准,Clang 拒绝代码是正确的。

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

[...] 计算点或箭头之前的后缀表达式;这 该评估的结果,连同 id-expression, 确定整个后缀表达式的结果。

还有一个说明:

如果评估类成员访问表达式,则子表达式 即使结果对于确定 整个后缀表达式的值,例如,如果 id-expression 表示静态成员。

因此,子表达式 t2 被计算。 [expr.const]/2.9 表示表达式e 不能是核心常量表达式,如果评估它会导致评估

一个引用变量或数据成员的id-expression 类型,除非引用具有先前的初始化并且

  • 用常量表达式初始化或
  • 它的生命周期从e 的评估开始;

t2 指的是不满足项目符号的引用类型的变量,因此t2.m 不是常量表达式,因为它不是核心常量表达式。


N4594 的所有引用,当前发布的工作草案。文字自 C++11 起略有变化,但本例中的含义是相同的。

【讨论】:

  • 谢谢。有人为 gcc 提交错误报告吗?
  • @ClaasBontus 我没有。通过错误数据库搜索将是有序的,但到目前为止我没有时间这样做。
  • 可能是Bug 39970
  • @ClaasBontus 相关,但我认为您的示例并非严格重复。使用该示例中的名称,如果我们尝试实例化template_blah&lt;&gt;(将使用默认模板参数)或template_blah&lt;global.member&gt;,GCC 将正确诊断错误(即使是struct blah,避免访问控制错误)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-05-02
  • 2013-08-26
  • 1970-01-01
  • 1970-01-01
  • 2019-12-02
  • 2016-01-18
  • 1970-01-01
相关资源
最近更新 更多