gpt4 book ai didi

C++:将 constexpr lambda 初始化为 constexpr/非 constexpr 变量

转载 作者:行者123 更新时间:2023-12-04 14:03:07 25 4
gpt4 key购买 nike

我正在阅读 Nicolai M. Josuttis 所著的“C++ 17 The Complete Guide”一书,无法理解以下示例

auto squared1 = [](auto val) constexpr { // example 1. compile-time lambda calls
return val * val;
};

及其声明

If (only) the lambda is constexpr it can be used at compile time,but squared1 might be initialized at run time, which means that someproblems might occur if the static initialization order matters (e.g,causing the static initialization order fiasco).

作者建议考虑以下方案

constexpr auto squared = [](auto val) constexpr {
return val * val;
};

意味着它将以某种方式避免之前的问题。

我不明白第一个例子关于初始化顺序的问题,因此无法理解作者的解决方案如何改进它。您能否解释一下并举一个例子来说明第一个例子的缺点?

最佳答案

语句auto square1 = 初始化一个全局变量,甚至不是常量。这是一个运行时变量,您可以对其进行变异、分配以及可能的其他内容。

你可以像这样初始化这样的变量:

auto returnMeALambda() {
int capture = rand() % 2;

return [capture](auto val) {
return val * val + capture;
}
}

auto square1 = returnMeALambda();

如您所见,returnMeALambda 的代码是严格运行时的,因此 square1 在运行时被强制初始化。

这些变量没有在编译时可用的值。编译器可能会在运行时很好地初始化它,即使不是被迫的。这在运行时有成本,并且使用 static initialization order fiasco ,从技术上讲,您可以在初始化之前使用 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 的值被编码在可执行二进制代码中。
  • 使变量值在编译时可用。您现在可以在 constexpr 上下文中使用该变量。

第二点是作者寻求解决方案的属性。该变量保证它永远不会在运行时初始化,因为该值在编译时可用并保证由编译器进行常量初始化。


请注意,在 C++20 中,您可以单独应用第二点,而无需使用 constinit 将值强制为 const。

constinit int value = 9;

现在编译器被迫使用常量初始化来初始化值,而且变量在运行时是可变的。这有效地解决了初始化顺序失败的问题,因为您可以不断地初始化您的变量。

关于C++:将 constexpr lambda 初始化为 constexpr/非 constexpr 变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69393323/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com