制作 lambda constexpr 的要求是什么?

What are the requirements to make a lambda constexpr?

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

auto lam = [<i>捕获列表</i>](<i>args</i>){<i>body</i>}

对此:

constexpr auto lam = [<i>捕获列表</i>](<i>args</i>){<i>body</i>}

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

Here 我读了

A constexpr variable must satisfy the following requirements:

  • its type must be a LiteralType.
  • it must be immediately initialized
  • the full-expression of its initialization, including all implicit conversions, constructors calls, etc, must be a constant expression
  • [a C++20-specific condtion]

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

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

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

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

its type must be a LiteralType.

lambda 的 LiteralType 要求实际上意味着所有捕获的成员也必须是 non-volatile 文字类型。定义一个 lambda 等同于定义一个匿名 struct,其中捕获的变量是成员。

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

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

当我们将 lambda 视为具有调用运算符的 struct 时,所有这些要求的含义也变得显而易见。我们无法捕获 non-literal 类型,因为这需要在此 struct 中存储 non-literal 类型。这在 constexpr 环境中是不可能发生的。

the full-expression of its initialization, including all implicit conversions, constructors calls, etc, must be a constant expression

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