基础语法
[capture-list](parameter-list) -> return-type {
// 函数体
}
两种递归 Lambda 写法对比
1. 使用 std::function
的递归 Lambda(C++11)
#include <functional>
std::function<int(int, int)> dfs = [&](int i, int j) -> int {
// 基本情况
if (i == 0 || j == 0) return 0;
// 递归调用必须通过 dfs 名称
return dfs(i-1, j) + dfs(i, j-1);
};
特点:
- 需要包含
<functional>
头文件 - 有运行时开销(类型擦除)
- 适用于 C++11 及以后版本
- 递归调用必须使用变量名
dfs
2. 使用显式对象参数的递归 Lambda(C++23)
auto dfs = [&](this auto&& self, int i, int j) -> int {
// 基本情况
if (i == 0 || j == 0) return 0;
// 递归调用通过 self 参数
return self(i-1, j) + self(i, j-1);
};
特点:
- 不需要
std::function
,零额外开销 - 需要 C++23 支持
- 更高效,直接使用 lambda 类型
- 递归调用通过参数
self
进行 auto&& self
是通用引用,可以完美转发
算法题常见用法
记忆化搜索示例
// C++23 风格
auto dfs = [&](this auto&& self, int i, int j, auto& memo) -> int {
if (memo[i][j] != -1) return memo[i][j];
if (i == 0 || j == 0) return memo[i][j] = 0;
return memo[i][j] = self(i-1, j, memo) + self(i, j-1, memo);
};
// C++11 风格
std::function<int(int, int, vector<vector<int>>&)> dfs = [&](int i, int j, auto& memo) -> int {
if (memo[i][j] != -1) return memo[i][j];
if (i == 0 || j == 0) return memo[i][j] = 0;
return memo[i][j] = dfs(i-1, j, memo) + dfs(i, j-1, memo);
};
二叉树遍历示例
// C++23 风格
auto traverse = [&](this auto&& self, TreeNode* root) -> void {
if (!root) return;
self(root->left); // 递归调用
self(root->right);
};
捕获模式总结
捕获方式 | 说明 | 算法题常用场景 |
---|---|---|
[&] | 引用捕获所有变量 | 需要修改外部变量(如记忆化数组) |
[=] | 值捕获所有变量 | 需要只读访问外部变量(较少使用) |
[var] | 值捕获特定变量 | 需要特定变量的副本 |
[&var] | 引用捕获特定变量 | 需要修改特定变量 |
[this] | 捕获当前类对象(类内定义 lambda 时) | 类方法中使用 |
[&, var] | 引用捕获所有变量,但值捕获 var | 大部分变量需要修改,个别需要副本 |
[=, &var] | 值捕获所有变量,但引用捕获 var | 大部分变量只读,个别需要修改 |
何时使用哪种写法
-
优先使用 C++23 风格(如果编译器支持):
- 性能更好
- 递归调用更直观
- 不需要额外头文件
-
使用 std::function 风格:
- 需要支持 C++11/14/17
- 需要将 lambda 存储在容器中或作为参数传递
- 需要运行时多态(不同类型 lambda 统一存储)
性能提示
- 在递归深度较大时,C++23 风格通常更快
- 避免在循环中创建 std::function(会有重复分配开销)
- 对于简单算法,直接使用普通函数可能更高效
示例题目
斐波那契数列
// C++23 风格
auto fib = [](this auto&& self, int n) -> int {
if (n <= 1) return n;
return self(n-1) + self(n-2);
};
// C++11 风格
std::function<int(int)> fib = [&](int n) -> int {
if (n <= 1) return n;
return fib(n-1) + fib(n-2);
};