首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++:将constexpr初始化为constexpr/非constexpr变量

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

Stack Overflow用户
提问于 2021-09-30 13:44:00
回答 1查看 98关注 0票数 3

我正在阅读NicolaiM.Josuttis的"C++ 17 --完整指南“一书,无法理解下面的例子

代码语言:javascript
复制
auto squared1 = [](auto val) constexpr { // example 1. compile-time lambda calls
  return val * val;
};

以及对它的陈述

如果(仅) lambda是constexpr,它可以在编译时使用,但是squared1可能在运行时被初始化,这意味着如果静态初始化顺序重要(例如,导致静态初始化顺序失败),可能会出现一些问题。

作者建议考虑以下解决方案

代码语言:javascript
复制
constexpr auto squared = [](auto val) constexpr {
  return val * val;
};

这意味着它可以在某种程度上避免以前的问题。

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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-09-30 15:10:44

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

您可以很好地初始化这样的变量:

代码语言:javascript
复制
auto returnMeALambda() {
    int capture = rand() % 2;

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

auto square1 = returnMeALambda();

正如您所看到的,returnMeALambda的代码严格地是运行时的,因此在运行时强制初始化square1

这些变量没有一个在编译时可用的值。编译器很可能会在运行时初始化它,即使不是被迫的。这在运行时是有代价的,对于静态初始化顺序失败,您可以在它被初始化之前在技术上使用lambda,甚至可以在初始化之前使用另一个全局的:

代码语言:javascript
复制
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。

代码语言:javascript
复制
constinit int value = 9;

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

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69393323

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档