"constexpr"变量"used in its own initializer":Clang与GCC

`constexpr` variable "used in its own initializer": Clang vs. GCC

本文关键字:Clang GCC initializer its constexpr 变量 used in own      更新时间:2023-10-16

这个问题似乎与现有问题有关,但我不理解答案中提供的"可移植的解决方法"(涉及const auto this_ = this;),而且我认为下面的例子更容易理解。

我正在播放以下C++17代码片段(实时演示):

#include <iostream>
struct Test {
const char* name_{nullptr};
const Test* src_{nullptr};
constexpr Test(const char* name) noexcept
: name_{name}
{}
constexpr Test(const Test& src) noexcept
: src_{&src}
{
name_ = src_->name_;
src_ = nullptr;
}
};
template<char c>
void print_constexpr_char() {
std::cout << c << std::endl;
}
int main() {
constexpr const char* in = "x";
constexpr auto foo = Test{in};
constexpr auto bar = Test{foo};
std::cout << bar.name_ << std::endl;
print_constexpr_char<bar.name_[0]>();
return 0;
}

GCC 7.2编译失败,而Clang 5.0.0没有发现任何问题。GCC错误本质上读取

错误:"bar"的值在常量表达式中不可用

注意:"bar"在其自身的初始值设定项中使用

在意识到删除最终的print_constexpr_char会使代码编译后,我更加困惑,尽管它仍然包含GCC经常抱怨的行constexpr auto bar = Test{foo};("在其自己的初始化器中使用")。

  1. 这里哪个编译器是正确的
  2. 如何理解GCC注释(如果不是bug的话),即"在自己的初始值设定项中使用"是有害的,如果结果随后被用于常量表达式中
  3. 在将正在构建的对象转换为可以存储在constexpr变量中的最终状态之前,是否有一种有效的方法/解决方法可以使用constexpr构造函数中的指针作为中间阶段

GCC拒绝代码是正确的(但是错误消息可能需要一些工作)。除非变量具有静态存储持续时间,否则不能在常量表达式中使用该变量的地址。

foo不是静态的。如果你把它移到main之外,一切都会好起来的。演示

下面标记的线是问题所在:

constexpr Test(const Test& src) noexcept
: src_{&src} <--- That

标准参考:(强调矿)

[expr.const]

常量表达式是指允许的实体的glvalue核心常量表达式常量表达式(定义如下)的结果,或值满足的prvalue核心常量表达式以下约束:

(5.2)--如果值为指针类型,则包含具有静态存储持续时间的对象的地址超过该对象末尾的地址(8.7)、函数的地址或空指针值,