2016-12-29 38 views
2

此代码被clang拒绝,因为t.n不是编译时常量。为什么不能将constexpr成员用于static_assert?

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

但g ++放过这个。

哪个是符合标准的行为?

还有一个奇怪的事实是,如果我改变test的说法从0​​到T t,这将建立在双方。 关于常量的变化是什么?

(我怕标题可能无法正确描述这个问题,或详细,随时给我更适合标题)

回答

1

我相信,(但有低可信度)是铛是正确的,因为根据标准,芯常量表达式可以包含:

引用参考类型的变量或数据成员的ID-表达除非引用具有之前的初始化,要么

- 使用常量表达式初始化或

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

t是参考类型的变量。假设(就像我这样做,低置信度),“在初始化之前”意味着初始化在词法上处于希望常量表达式发生的位置,因为参数的初始化发生在调用者的作用域内,t会不满足这个要求,所以t.n确实不能用于常量表达式。

如果参数类型更改为T,则此不合格项目符号点不再适用。

(即使你接受我的解释,仍然存在不确定性;见CWG 2186

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); 
} 
相关问题