以下 C++11 程序:
int x = 42;
void f()
{
int y = 43;
static_assert(&x < &y, "foo");
}
int main()
{
f();
}
不能用 gcc 4.7 编译,因为它抱怨:
error: ‘&y’ is not a constant expression
这符合我的直觉。的地址y
可能随着每次调用而改变f
,所以在翻译过程中当然不能计算出来。
然而,5.19 [expr.const] 中的所有要点似乎都没有阻止它成为一个常量表达式。
我看到的仅有的两个竞争者是:
左值到右值的转换...
但除非我弄错了(?),否则程序中没有左值到右值的转换。
和
an
id-expression
引用变量 [snip],除非:
- 它用常量表达式初始化
即y
- 它使用常量表达式进行初始化43
。
那么这是标准中的错误,还是我遗漏了什么?
更新:
这令人困惑,但我认为我已经掌握了它,所以让我举一个例子来展示正在发生的事情:
int x = 42;
void f()
{
int y = 43;
// address constant expressions:
constexpr int* px = &x; // OK
constexpr int* py = &y; // ERROR: pointer context for local variable
// boolean constant expressions:
constexpr bool bx = &x; // OK
constexpr bool by = &y; // OK
// comparison constant expressions:
constexpr bool eq = (&x == &y); // OK
constexpr bool lt = (&x < &y); // ERROR: undefined behaviour disqualifies
a constant expression
}
int main()
{
f();
}
首先区分核心常量表达式(5.19p2)和常量表达式(5.19p4)。具体来说,常量表达式的子表达式只需是核心常量表达式,而不是常量表达式。也就是说,作为常量表达式是完整表达式的属性,而不是子表达式。它还需要查看使用完整表达式的上下文。
因此,事实证明 gcc 错误具有误导性。首先&y
在某些情况下可能是一个常量表达式。其次,&x < &y
不是常量表达式的原因是因为比较不相关的指针,而不是子表达式&y
。