constexpr 与 lambda 表达式的 C++ 用法

C++ usage of constexpr with lambda expression

我正在阅读书 C++17 - The Complete Guide,在第 6.1 节 constexpr lambda 中,作者给出了两个示例:

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

constexpr auto squared2 = [](auto val) { // example 2. compile-time initialization
  return val * val;
};

并且说这两个在某种意义上是不同的 example 1 在编译时评估并且 示例2在编译时初始化。


然后作者发表了以下我不完全理解的陈述:

If (only) the lambda is constexpr it can be used at compile time, but If the (closure) object initialized by the lambda is constexpr, the object is initialized when the program starts but the lambda might still be a lambda that can only be used at run time (e.g., using static variables). Therefore, you might consider declaring:

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

上面的说法到底是什么意思?

很明显,constexpr关键字出现在squared2 lambda对象的初始化语句和示例3[=41中的lambda表达式本身=] 但我不明白这个比 示例 1 有什么优势。

事实是,一个 auto 声明的对象不采用其初始化表达式的 constexpr'ness,仅采用其类型; constexpr 是该类型的 而不是 的一部分。参见:

所以,假设我有:

auto five_squared = 25;

值25非常constexpr,即可以在compile-time处使用。然而 - five_squared 不能 在 compile-time 上使用。您仍然需要指明它是 constexpr (*).

这与您的 lambda 基本相同。 lambda 是 on-the-spot-defined class 和 operator() 的实例。如果您不自己创建一个变量,那么 squared 不会成为一个 constexpr 变量。


(*) - 请注意,由于 C++ 语言中的特殊规则,使用 constant-expression 初始化的 const 整数自动为 constexpr,所以你 可以 只写 const auto 并隐含地得到 constexpr 。然而,这是一个需要记住的棘手 special-case,所以如果你想创建一个变量 constexpr,我建议明确说明。感谢@cigien 提出这一点。