使用constinit变量初始化constexpr变量

gez*_*eza 5 c++ c++20

看这个小例子:

constinit int a = 0;
constexpr int b = a;
Run Code Online (Sandbox Code Playgroud)

clang不会编译它(godbolt):

2:15:错误:constexpr变量“ b”必须由常量表达式初始化

这是正确的诊断程序吗?

如果是,标准为何不允许这样做?我了解,该a值可能会在运行期间(甚至在动态初始化期间)发生变化,但是在常量初始化时,其值是已知的,因此可以将其用于初始化b

Bar*_*rry 4

是的,诊断是正确的。constexpr变量必须用常量表达式初始化,并且a不是常量表达式(它是可变变量)。

\n\n

constinit( P1143 )的目的是,如果变量的初始化不是常量,则强制变量声明格式错误。它不会改变变量本身的任何内容,比如它的类型或任何东西(以constexpr隐式的方式const)。愚蠢的例子:

\n\n
struct T {\n    int i;\n    constexpr T(int i) : i(i) { }\n    T(char c) : i(c) { }\n};\n\nconstinit T c(42); // ok\nconstinit T d(\'X\'); // ill-formed\n
Run Code Online (Sandbox Code Playgroud)\n\n

这就是全部constinit,唯一真正的规则是[dcl.constinit]/2

\n\n
\n

如果用说明符声明的变量constinit具有动态初始化 ([basic.start.dynamic]),则程序格式错误。\n [注意constinit说明符确保变量在静态初始化期间初始化 ([basic.start.static] ]).\n \xe2\x80\x94尾注\n ]

\n
\n\n

const inconstinit仅指初始化,不是变量,也不是任何类型。请注意,它也不会更改执行的初始化类型,它只是诊断是否执行了错误的类型。

\n\n

在:

\n\n
constinit int a = 0;\nconstexpr int b = a;\n
Run Code Online (Sandbox Code Playgroud)\n\n

0是一个常量表达式,因此 的初始化a是格式良好的。一旦我们超越了这一点,说明符就不会做任何事情。它相当于:

\n\n
int a = 0; // same behavior, a undergoes constant initialization\nconstexpr int b = a;\n
Run Code Online (Sandbox Code Playgroud)\n\n

这显然是不正确的。

\n\n
\n\n
\n

但在常量初​​始化时,它的值是已知的,因此可以用它来初始化b

\n
\n\n

当然,此时此刻。关于什么:

\n\n
constinit int a = 0;\ncin >> a;\nconstexpr int b = a;\n
Run Code Online (Sandbox Code Playgroud)\n\n

这显然是飞不起来的。允许这一点需要扩展常量表达式(在我看来,这已经是标准中最复杂的规则)以允许非常量变量,但只能在初始化后立即使用?复杂性似乎不值得,因为你总是可以写:

\n\n
constexpr int initializer = 0;\nconstinit int a = initializer;\nconstexpr int b = initializer;\n
Run Code Online (Sandbox Code Playgroud)\n