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

Using an enum as a constant expression. Which compiler is right?

本文关键字:编译器 表达式 枚举 常量      更新时间:2023-10-16

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

这个问题可以通过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
    }
};

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

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

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

还有一个注释:

如果计算类成员访问表达式,则子表达式 即使不需要结果来确定 整个后缀表达式的值,例如,如果 id-expression 表示静态成员。

因此,将计算子表达式t2。[expr.const]/2.9 表示表达式e不能是核心常量表达式,如果计算表达式

会导致
引用

引用的变量或数据成员的 ID 表达式 类型,除非引用具有前面的初始化,并且

  • 它使用常量表达式或
  • 它的生命周期始于对e的评估;

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


所有引文均来自N4594,当前发布的工作草案。自 C++11 以来,文本略有变化,但在这种情况下的含义是相同的。