MSVC 接受以 nullptr 初始化的指向 int 的常量指针作为常量表达式

问题描述 投票:0回答:1

在阅读了有关常量表达式的内容后,我编写了以下示例,该示例使用 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。

c++ pointers language-lawyer compile-time-constant constant-expression
1个回答
1
投票

根据

[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
 而不应用任何转换。在这种情况下,它将是一个常量表达式。

© www.soinside.com 2019 - 2024. All rights reserved.