为什么constexpr成员不能用于static_assert?

时间:2016-12-29 02:05:24

标签: c++ constexpr

此代码被clang拒绝,因为a不是编译时常量。

t.n

但是g ++让这一切。

符合标准的行为是什么?

另一个奇怪的事实是,如果我将template<int N> struct s{ constexpr static int n = N; }; template<typename T> void test(T& t){ static_assert(t.n == 1); } int main(){ s<1> str; test(str); } 的论点从test更改为T& t,这将基于两者。 关于const-ness有什么改变?

(我担心标题可能无法正确或详细地描述这个问题。请随意给我更合适的标题)

2 个答案:

答案 0 :(得分:1)

我相信(但信心不足)Clang是正确的,因为根据标准,核心常量表达式可能包含:

  

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

     

- 用常量表达式

初始化      

- 它是一个对象的非静态数据成员,其生命周期始于t的评估;

t是引用类型的变量。假设(正如我所做的那样,低信心)&#34;在初始化之前&#34;表示在将要发生的常量表达式的范围内在词法上的初始化,因为参数的初始化发生在调用者的范围内,t.n不满足此要求,因此T确实不能用于常数表达式。

如果参数类型更改为select * from tbl where a IN ( select a from tbl group by a having count(*)>1 ) and b!=1 UNION ALL select * from tbl where a IN ( select a from tbl group by a having count(*)=1 ) ,则此不合格项目符号点将不再适用。

(即使你接受我的解释,仍然存在歧义;见CWG 2186

答案 1 :(得分:0)

我不知道编译错误的原因但是如果你改变代码使用范围解析运算符来访问静态变量,那么代码将在两个编译器上编译

#include <iostream>

using namespace std;

template<int N>
struct s{
    constexpr static int n = N;
};

template<typename T>
void test(T&){
    static_assert(T::n == 1, "blah");
}

int main(){
  s<1> str;
  test(str);
}