【问题标题】:What are the requirements to make a lambda constexpr?制作 lambda constexpr 有什么要求?
【发布时间】:2020-12-24 00:02:16
【问题描述】:

多次,在代码审查中,我被告知将 contexpr 添加到某个命名的 lambda 闭包声明中,即我被告知要更改此内容

auto lam = [<i>capture list</i>](<i>args</i>){<i>body</i>}

到这里:

constexpr auto lam = [<i>capture list</i>](<i>args</i>){<i>body</i>}

因此,我想了解允许将 lambda 闭包声明为 constexpr 的条件,以便我可以自主进行此更改。

Here我读到了

constexpr 变量必须满足以下要求:

  • 它的类型必须是 LiteralType。
  • 必须立即初始化
  • 其初始化的完整表达式,包括所有隐式转换、构造函数调用等,必须是常量表达式
  • [特定于 C++20 的条件]

我看到第二个条件已得到验证,但我希望得到一些帮助来理解第一个条件,尤其是第三个条件。

关于第一个条件,在LiteralType 页面上,我了解对于成为 LiteralType 的变量来说,成为 可能具有析构函数的 cv 限定类类型就足够了(怎么可能没有?)并且是一个闭包类型(上面的lam就是这种情况),所有非静态数据成员和基类都是非volatile 文字类型(我不确定最后一部分与 lambdas 的关系)。

最重要的是,我想了解我如何通过检查来理解我是否可以制作 lambda constexpr

【问题讨论】:

  • 页面没有说“有一个析构函数”,它说“有一个普通的析构函数”(对于 C++17)或者“有一个 constexpr 析构函数”(C++20)

标签: c++ lambda c++17 constexpr c++20


【解决方案1】:

唯一决定 lambda 是否可以是 constexpr 的是捕获列表。主体可以是非constexpr 并且constexpr lambda 仍然可以具有像std::string 这样的参数,它们也不是文字类型。

它的类型必须是 LiteralType。

对 lambda 的 LiteralType 要求实际上意味着所有捕获的成员也必须是非易失性文字类型。定义一个 lambda 相当于定义一个匿名的struct,其中捕获的变量是成员。

constexpr int x = 0;
constexpr auto lam = [x](){};

// equivalent to:
struct Lam {
    int x;
    void operator()() {}
};
constexpr Lam lam2{x};

当我们想到带有调用运算符的 structs 这样的 lambdas 时,所有这些要求的含义也变得显而易见。我们无法捕获非文字类型,因为这需要在此struct 中存储非文字类型。这不可能在 constexpr 上下文中发生。

其初始化的完整表达式,包括所有隐式转换、构造函数调用等,必须是常量表达式

再一次,这基本上表明捕获变量必须以constexpr 方式发生。所有捕获的变量必须是constexpr,否则初始化不会。事实上,constexpr 变量都是隐式捕获的。 所以这真正的意思是,当它没有捕获列表时,可以将 lambda 设为 constexpr,或者可以省略捕获列表。

【讨论】:

  • ... 而 lambda 不是 mutable (因为那样会很傻)。
猜你喜欢
  • 2015-02-12
  • 2019-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-30
  • 2017-09-25
  • 1970-01-01
  • 2020-02-28
相关资源
最近更新 更多