constexpr int* ptr =&i 在 msvc 中编译,但不能在 clang 和 gcc 中编译

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

我正在使用

这里
列出的书籍学习constexpr变量。特别是我在 C++ Primer 中读到:

声明的变量

constexpr
是隐式 const,必须使用常量表达式进行初始化。

现在,为了进一步明确我的概念并检查我是否正确理解了这些内容,我编写了以下简单的程序,该程序使用 msvc 进行编译,但不使用 gcc 和 clang 进行编译: 演示

int main(void)
{
   int i = 0;
   constexpr int *ptr= &i; //compiles with msvc but not with clang and gcc 
}

所以,我的问题是哪个编译器就在这里(如果有的话)?

c++ pointers reference language-lawyer constexpr
2个回答
2
投票

该程序是格式错误并且msvc在未给出诊断方面是错误的(这已在最新版本的msvc中修复)。这是因为

i
不是静态分配的对象,因此它的地址不是恒定的。基本上,因为我们只能从
constexpr
文字或文字
nullptr
或从具有固定地址
的对象的地址初始化 
0 指针,并且在您的示例中,i
 不是一个对象有固定地址,因此 
&i
 
不是常量表达式

这可以从

expr.const#11 中看出:

常量表达式可以是泛左值核心常量表达式,它引用作为常量表达式(如下定义)允许的结果的实体,或者是prvalue核心常量表达式,其值满足以下约束

  • 如果该值是指针类型,则它包含具有静态存储持续时间的对象的地址,超过该对象末尾的地址([expr.add]),非立即函数的地址,或空指针值,
如果实体是具有静态存储持续时间的对象,并且不是临时对象或者是其值满足上述约束的临时对象,或者如果它是非立即函数,则该实体是常量表达式的允许结果。

(强调我的)

这意味着有两种方法可以解决这个问题。

首先是您可以在static

前面添加
i
以使其成为本地静态。 
第二是将i
的定义移至主函数之外的全局范围。在这两种情况下(如下所示),
i
将具有
静态存储持续时间,因此根据上面引用的语句,&i
现在将是一个常量表达式。


方法1

int main() { //-vvvvvv------------->static added here so that i now has static storage duration static int i = 0; constexpr int *ptr= &i; //works now }
方法2

int i = 0; //make i global so that i now has static storage duration int main() { constexpr int *ptr= &i; //works now }
这是 msvc 错误报告:

MSVC 编译无效 constexpr int*ptr= &i

 其中 i 是本地非静态对象


0
投票
截至 2023 年 8 月 9 日,此问题已得到修复,不再是问题。更新您的编译器。

请参阅:

https://developercommunity.visualstudio.com/t/MSVC-compiles-invalid-constexpr-intptr/10173848,它指向https://developercommunity.visualstudio.com/t/Address-of-local-变量不应该是/1142306

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