使用 constinit 变量初始化 constexpr 变量
Using constinit variable to initialize a constexpr variable
看看这个小例子:
constinit int a = 0;
constexpr int b = a;
Clang没有编译它(Godbolt(:
2:15:错误:constexpr 变量"b"必须由常量表达式初始化
这是正确的诊断吗?
如果是,为什么标准不允许这样做?我知道,a
的值可能会在运行期间(甚至在动态初始化期间(发生变化,但在常量初始化时,它的值是已知的,因此可用于初始化b
。
是的,诊断是正确的。constexpr
变量必须使用常量表达式初始化,并且a
不是常量表达式(它是可变变量(。
constinit
(P1143( 的目的是在变量声明的初始化不是恒定的情况下强制变量声明格式不正确。它不会更改变量本身的任何内容,例如它是类型或任何内容(以隐式const
的方式constexpr
(。愚蠢的例子:
struct T {
int i;
constexpr T(int i) : i(i) { }
T(char c) : i(c) { }
};
constinit T c(42); // ok
constinit T d('X'); // ill-formed
这就是constinit
的全部目的,唯一真正的规则是[dcl.constinit]/2:
如果使用
constinit
说明符声明的变量具有动态初始化([basic.start.dynamic](,则程序格式不正确。 [注意:constinit
说明符确保在静态初始化期间初始化变量([basic.start.static](。 —尾注]
constinit
中的 const 仅指初始化,不指变量,也不指任何类型的。请注意,它也不会更改执行的初始化类型,它只是诊断是否执行了错误的初始化类型。
在:
constinit int a = 0;
constexpr int b = a;
0
是一个常量表达式,因此a
的初始化格式正确。一旦我们克服了这一点,说明符就不做任何事情了。它相当于:
int a = 0; // same behavior, a undergoes constant initialization
constexpr int b = a;
这完全是格式错误的。
但是在常量初始化时,它的值是已知的,因此可用于初始化
b
。
当然,此时此刻。怎么样:
constinit int a = 0;
cin >> a;
constexpr int b = a;
这显然不会飞。允许这一点需要扩展常量表达式是什么(在我看来,已经是标准中最复杂的规则(以允许非常量变量,但仅在初始化后立即?复杂性似乎不值得,因为您可以随时编写:
constexpr int initializer = 0;
constinit int a = initializer;
constexpr int b = initializer;
constexpr
无一例外地结合了constinit
和const
。
constinit
强制使用编译时常量表达式进行初始化,并在静态初始化期间强制初始化,不允许动态初始化。不过,它不会以任何方式更改变量本身。
const
禁止更改变量,但可以通过mutable
成员来削弱变量。
两者共同使其成为编译时常量表达式。
总之,是的,诊断是正确的。
这是正确的诊断吗?
我会说是的。根据 cpp 偏好:
constinit - 指定变量必须具有静态初始化, 即零初始化和常量初始化,否则 程序格式不正确。
静态(常量(初始化和常量表达式是不同的概念,因为常量表达式可以在常量初始化中使用,但不能以相反的方式使用。constinit
不应该与const混淆。这意味着初始化(仅(是恒定的。
但是,constinit const
可以在constexpr
中使用,并且它们应该是相同的。
反例:
constinit int a = 0;
struct X{
X() {
a = 4;
}
};
X x{};
constexpr int b = a;
b
应该是什么? 关键是,在看到b
之前,a
可以以非常量的方式进行更改。
- vs 2015 constexpr变量不恒定,但与2019相比还好吗
- 静态 constexpr 类成员变量对多线程读取是否安全?
- 在非 constexpr 函数中作为左值传递的变量上使用 'constexpr' 函数
- constexpr函数中的静态constexpr变量
- 有时可以在 constexpr 上下文中使用非 constexpr 变量?
- 错误:constexpr 变量'struct2Var'必须由常量表达式初始化
- 静态 constexpr 成员变量初始化
- 是否使用静态 constexpr 变量 odr?
- constexpr 函数在编译时获取值,即使我的变量不是 constexpr
- 全局和局部变量初始化与 constexpr 的差异背后的基本原理
- 静态 constexpr 全局变量
- 是否可以将变体的索引作为 constexpr 变量获取?
- 奇怪的错误 C2131 与 constexpr 声明变量
- 我可以定义一个 constexpr 匿名/未命名变量吗?
- 非 constexpr 变量模板的开销是否为零?
- Constexpr变量不是编译时值
- 为什么非成员静态 constexpr 变量不是隐式内联的?
- 在 C++17 中修改 constexpr 函数中的全局变量
- 是否可以使用"if constexpr"来声明具有不同类型和init-expr的变量
- 使用 constinit 变量初始化 constexpr 变量