我正在阅读NicolaiM.Josuttis的"C++ 17 --完整指南“一书,无法理解下面的例子
auto squared1 = [](auto val) constexpr { // example 1. compile-time lambda calls
return val * val;
};以及对它的陈述
如果(仅) lambda是
constexpr,它可以在编译时使用,但是squared1可能在运行时被初始化,这意味着如果静态初始化顺序重要(例如,导致静态初始化顺序失败),可能会出现一些问题。
作者建议考虑以下解决方案
constexpr auto squared = [](auto val) constexpr {
return val * val;
};这意味着它可以在某种程度上避免以前的问题。
我不理解关于初始化顺序的第一个示例的问题,因此无法理解作者的解决方案如何改进它。请你解释一下,并举例说明第一个例子的缺点。
发布于 2021-09-30 15:10:44
语句auto square1 =初始化全局变量,甚至不初始化常量。这是一个运行时变量,您可以对其进行变异、分配,并可能进行其他操作。
您可以很好地初始化这样的变量:
auto returnMeALambda() {
int capture = rand() % 2;
return [capture](auto val) {
return val * val + capture;
}
}
auto square1 = returnMeALambda();正如您所看到的,returnMeALambda的代码严格地是运行时的,因此在运行时强制初始化square1。
这些变量没有一个在编译时可用的值。编译器很可能会在运行时初始化它,即使不是被迫的。这在运行时是有代价的,对于静态初始化顺序失败,您可以在它被初始化之前在技术上使用lambda,甚至可以在初始化之前使用另一个全局的:
extern int baseval;
auto returnMeALambda() {
int capture = baseval + rand() % 2;
return [capture](auto val) {
return val * val + capture;
}
}
auto square1 = returnMeALambda();
int baseval = square1(2);这段代码将始终是未定义的行为,因为它总是使用未初始化的变量,无论初始化顺序如何。
作者提出的解决方案是将变量初始化为constexpr。在这种情况下,这样做有三件事:
const。您不能在运行时更改它的值。square1的值在可执行二进制代码中编码。第二点是作者所寻求的作为解决方案的属性。该变量保证不会在运行时被初始化,因为该值在编译时可用,并保证编译器的持续初始化。
请注意,在C++20中,您可以自己应用第二个点,而不必强制使用constinit将值设为const。
constinit int value = 9;现在编译器被迫使用常量初始化来初始化值,但在运行时变量也是可变的。这有效地解决了初始化顺序的失败,因为您可以常量地初始化变量。
https://stackoverflow.com/questions/69393323
复制相似问题