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

Cla*_*tus 6 c++ c++11

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

这个问题可以通过交换行来解决// 1A<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
    }
};
Run Code Online (Sandbox Code Playgroud)

bog*_*dan 4

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

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

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

还有一个注释:

如果对类成员访问表达式进行求值,则即使不需要结果来确定整个后缀表达式的值,也会发生子表达式求值,例如,如果 id 表达式表示静态成员。

因此,子表达式t2被求值。[expr.const]/2.9 表示如果对某个表达式e求值导致求值,则该表达式不能是核心常量表达式

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

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

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


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