此代码被 clang 拒绝,因为 t.n
不是编译时常量。
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
的参数从 T& t
更改为 T t
,这将建立在两者之上。
常量性发生了什么变化?
(恐怕标题可能无法正确或详细地描述这个问题。请随意给我更合适的标题)
最佳答案
我相信(但信心不足)Clang 是正确的,因为根据标准,核心常量表达式可能不包含:
an id-expression that refers to a variable or data member of reference type unless the reference has a preceding initialization and either
— it is initialized with a constant expression or
— it is a non-static data member of an object whose lifetime began within the evaluation of
e
;
和t
是引用类型的变量。假设(正如我所做的那样,信心不足)“前面的初始化”意味着在可能的常量表达式发生的点上词法上的初始化,因为参数的初始化发生在调用者的范围内,t
不满足这个要求,所以t.n
确实不能用在常量表达式中。
如果参数类型更改为 T
,则此取消资格的要点不再适用。
(即使您接受我的解释,仍然存在歧义;请参阅 CWG 2186 )
关于c++ - 为什么 constexpr 成员不能用于 static_assert?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41372217/