我正在使用
这里列出的书籍学习
constexpr
变量。特别是我在 C++ Primer 中读到:
声明的变量
是隐式 const,必须使用常量表达式进行初始化。constexpr
现在,为了进一步明确我的概念并检查我是否正确理解了这些内容,我编写了以下简单的程序,该程序使用 msvc 进行编译,但不使用 gcc 和 clang 进行编译: 演示
int main(void)
{
int i = 0;
constexpr int *ptr= &i; //compiles with msvc but not with clang and gcc
}
所以,我的问题是哪个编译器就在这里(如果有的话)?
该程序是格式错误并且msvc在未给出诊断方面是错误的(这已在最新版本的msvc中修复)。这是因为
i
不是静态分配的对象,因此它的地址不是恒定的。基本上,因为我们只能从 constexpr
文字或文字 nullptr
或从具有固定地址的对象的地址初始化
0
指针,并且在您的示例中,i
不是一个对象有固定地址,因此
&i
不是常量表达式。 这可以从
expr.const#11 中看出:
(强调我的)常量表达式可以是泛左值核心常量表达式,它引用作为常量表达式(如下定义)允许的结果的实体,或者是prvalue核心常量表达式,其值满足以下约束:
如果实体是具有静态存储持续时间的对象,并且不是临时对象或者是其值满足上述约束的临时对象,或者如果它是非立即函数,则该实体是常量表达式的允许结果。
- 如果该值是指针类型,则它包含具有静态存储持续时间的对象的地址,超过该对象末尾的地址([expr.add]),非立即函数的地址,或空指针值,
这意味着有两种方法可以解决这个问题。
首先是您可以在static
前面添加
i
以使其成为本地静态。第二是将
i
的定义移至主函数之外的全局范围。在这两种情况下(如下所示),
i
将具有静态存储持续时间,因此根据上面引用的语句,
&i
现在将是一个常量表达式。
int main()
{
//-vvvvvv------------->static added here so that i now has static storage duration
static int i = 0;
constexpr int *ptr= &i; //works now
}
方法2int 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 是本地非静态对象
请参阅:
https://developercommunity.visualstudio.com/t/MSVC-compiles-invalid-constexpr-intptr/10173848,它指向https://developercommunity.visualstudio.com/t/Address-of-local-变量不应该是/1142306