在阅读了有关常量表达式的内容后,我编写了以下示例,该示例使用 msvc 进行编译,但被 gcc 和 clang 拒绝。
int *const ptr2 = nullptr;
static_assert(!ptr2); //msvc passes but both gcc and clang rejects/fails this
int main()
{
}
正如我们所看到的,gcc 拒绝了代码:
<source>:2:15: error: non-constant condition for static assertion
2 | static_assert(!ptr2); //msvc passes but both gcc and clang rejects/fails this
| ^~~~~
<source>:2:15: error: the value of 'ptr2' is not usable in a constant expression
<source>:1:12: note: 'ptr2' was not declared 'constexpr'
另一方面,msvc 接受/编译程序。我想知道根据 C++ 标准哪个编译器是正确的。
请注意,我知道我可以使用
constexpr
kewyord,然后程序将与所有编译器一起编译。但我的问题是关于当前程序按照 C++ 标准的行为。另请注意,我使用的是 C++20。
根据
[expr.unary.op]/9,
!
的操作数根据上下文转换为 bool
。
应用 [conv.general]/4 这意味着我们获得了
bool
值,就像通过使用 初始化变量
_
一样
bool _(ptr2);
Per [dcl.init.general]/16.9 使用标准转换序列将初始化表达式
ptr2
转换为 bool
。
为了构造该序列,需要进行左值到右值的转换,因为到
bool
的标准转换都需要纯右值(请参阅 [conv]),但 ptr2
是左值表达式。
根据 [expr.const]/5.8,在常量表达式中不允许左值到右值的转换,因为
ptr2
的生命周期不是在常量表达式求值期间开始的,也不能在常量表达式中使用,仅适用于 constexpr
变量和
const
限定的积分/枚举类型变量(请参阅[expr.const]/4 和 [expr.const]/3) 所以 MSVC 是“不正确的”,而其他编译器是正确的。
ptr2
的初始化并不重要。
但是,如果变量本身的类型是
std::nullptr_t
,那么 [dcl.init.general]/16.8
) 将抢占 16.7。并且
bool
的值将 false
而不应用任何转换。在这种情况下,它将是一个常量表达式。