C++ 17 constexpr lambda表达式

C++ 17 constexpr lambda表达式

C++17 开始,lambda 表达式可以在满足条件时被当作 constexpr 使用。这个特性让 lambda 不再只是运行期的小函数对象,在一些场景下它也能参与编译期计算。

1. 什么是 constexpr lambda?

简单理解就是:如果一个 lambda 的函数体本身满足常量表达式要求,那么它就可以在编译期求值。

例如:

1
2
3
4
5
constexpr auto add = [](int a, int b) {
return a + b;
};

constexpr int value = add(1, 2);

这里的 add(1, 2) 就可以在编译期直接算出结果。

2. C++17 之前和之后的区别

在早期标准里,lambda 更多是运行时工具,虽然能写得很灵活,但不太适合做编译期运算。
到了 C++17,这方面明显宽松了不少,很多简单 lambda 都能自然地变成常量表达式。

这对模板元编程、编译期辅助计算、以及一些需要 constexpr 回调的小场景都比较有帮助。

3. 基本示例

3.1 最简单的编译期计算

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
using namespace std;

int main()
{
constexpr auto square = [](int x) {
return x * x;
};

constexpr int ret = square(5);
cout << ret << endl;
return 0;
}

输出:

1
25

3.2 作为辅助判断函数

1
2
3
4
5
constexpr auto isEven = [](int n) {
return n % 2 == 0;
};

static_assert(isEven(8), "8 should be even");

这里 static_assert 能通过,就说明这个 lambda 已经参与了编译期判断。

4. 使用场景

4.1 编译期辅助函数

有些逻辑写成普通 constexpr 函数也可以,但写成 lambda 更适合局部使用:

1
2
3
4
5
6
7
8
int main()
{
constexpr auto maxValue = [](int a, int b) {
return a > b ? a : b;
};

constexpr int ret = maxValue(3, 9);
}

这种写法适合“只在当前作用域内用一次”的编译期小工具。

4.2 配合 static_assert

1
2
3
4
5
constexpr auto inRange = [](int x) {
return x >= 0 && x <= 100;
};

static_assert(inRange(50), "value out of range");

4.3 模板中的局部逻辑

在模板函数里,lambda 有时比再额外写一个帮助函数更顺手。

5. 使用时的限制

虽然 constexpr lambda 很方便,但并不是所有 lambda 都能参与编译期计算。

5.1 不能做运行期才能确定的事情

例如:

  • 访问运行时输入
  • 动态分配资源
  • 调用非 constexpr 函数

这些都不适合放进编译期求值逻辑里。

5.2 捕获内容也要注意

如果你捕获的是一个运行期变量,那 lambda 即使写成 constexpr 形式,也未必能在编译期真正求值。

例如:

1
2
int x = 10;
auto func = [x]() { return x + 1; };

这里 x 是运行期变量,所以 func() 显然不是编译期常量表达式。

5.3 不是写了 constexpr 就一定编译期执行

这点和普通 constexpr 函数一样。
它的含义是“可以在编译期求值”,但实际是不是编译期执行,要看上下文是否要求常量表达式。

6. 和普通 constexpr 函数怎么选?

更适合用 constexpr 函数的情况

  • 逻辑需要复用很多次
  • 想要独立函数名
  • 接口需要更明确

更适合用 constexpr lambda 的情况

  • 只在局部作用域里用
  • 逻辑很小
  • 不想额外定义一个命名函数

7. 一个稍完整的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <array>
#include <iostream>
using namespace std;

int main()
{
constexpr auto calc = [](int a, int b, int c) {
return a * b + c;
};

constexpr int result = calc(2, 3, 4);
static_assert(result == 10, "result error");

cout << result << endl;
return 0;
}

总结

constexpr lambda 让 lambda 的用途从“运行期简化代码”进一步扩展到了“编译期辅助计算”。
它很适合写一些局部、短小、一次性的编译期逻辑。对于现代 C++ 来说,这算是一个不算大但很实用的增强点。