一文掌握 C++ Lambda 表达式(从仿函数到实战)
·
目录
一、从仿函数到 Lambda:背景理解
在 C++11 之前,我们常常用 仿函数(函数对象) 来实现可调用逻辑,例如:
struct Add {
int operator()(int a, int b) const {
return a + b;
}
};
Add add;
std::cout << add(2, 3); // 输出 5
这种写法虽然灵活,但需要显式定义一个类。
而 lambda 表达式 本质上是编译器帮你自动生成一个匿名仿函数类,
你只需要一行写法,就能获得同样的功能。
二、Lambda 表达式的基本语法
[capture](parameters) -> return_type {
// 函数体
};
示例
auto func = [](int a, int b) {
return a + b;
};
int ans = func(2, 3); // ans = 5
语法说明
| 部分 | 含义 |
|---|---|
[capture] | 捕获外部变量 |
(parameters) | 参数列表 |
-> return_type | 返回值类型(可省略) |
{...} | 函数体 |
三、Lambda 的真实类型是什么?
当你写下:
auto func = [](int a, int b) { return a + b; };
编译器会生成一个匿名类,大致如下:
class __Lambda {
public:
int operator()(int a, int b) const {
return a + b;
}
};
__Lambda func;
也就是说:lambda 是一个编译器生成的匿名类对象。
每个 lambda 都有唯一的类型,通常无法手动命名,所以我们用 auto 接收。
四、捕获外部变量(Capture)
1. 按值捕获 [x]
int x = 10;
auto f = [x]() { std::cout << x; };
f(); // 输出 10
按值捕获会拷贝 x 的当前值进入 lambda。
2. 按引用捕获 [&x]
int x = 10;
auto f = [&x]() { ++x; std::cout << x; };
f(); // 输出 11
std::cout << x; // 输出 11
按引用捕获会让 lambda 访问并修改外部变量。
3. 捕获所有变量
| 写法 | 含义 |
|---|---|
[=] | 按值捕获所有可访问的外部变量 |
[&] | 按引用捕获所有可访问的外部变量 |
也可以混用:
auto f = [a, &b]() { /* a按值,b按引用 */ };
五、Lambda 与 STL 算法
Lambda 在 STL 算法中极其常用,
例如 std::sort 中用于定义自定义排序规则。
示例:自定义升降序
bool reverse = true;
std::vector<int> v = {2, 1, 3, 5, 4};
std::sort(v.begin(), v.end(), [reverse](int a, int b) {
return reverse ? a > b : a < b;
});
如果改成 [&reverse],就能根据外部变量的动态变化改变排序逻辑。
六、Lambda 的 const 性质与 mutable
默认情况下,lambda 的调用运算符 operator() 是 const 的:
auto f = [x]() {
x++; // ❌ 错误,operator() 默认是 const
};
要让它可修改捕获的拷贝,需要加上 mutable:
int x = 10;
auto f = [x]() mutable {
x++;
std::cout << x; // 输出 11
};
f();
std::cout << x; // 外部的 x 仍是 10
| 状态 | 是否可修改捕获变量 | operator() 是否 const |
|---|---|---|
| 默认 | 否 | 是 |
使用 mutable | 是 | 否 |
七、总结与复习要点
| 知识点 | 关键内容 |
|---|---|
| 本质 | 编译器自动生成的匿名仿函数类 |
| 捕获方式 | [x] 按值; [&x] 按引用; [=] / [&] 批量捕获 |
| 返回类型 | 自动推导,可用 -> type 指定 |
| const 行为 | 默认 operator() 为 const,可用 mutable 去除 |
| 典型用途 | 回调、算法函数、线程任务、延迟执行 |
结语
Lambda 表达式是现代 C++ 的一项核心特性。
不仅让代码更简洁,也能更灵活地封装局部逻辑。
还能轻松地写出现代风格的 STL 算法、回调函数、线程任务和 GUI 信号槽。
免责声明
本文为个人学习笔记整理,仅供学习交流使用。
如因使用文中代码造成的任何后果,作者并不对此负责。
封面图来源于网络,如有侵权,请联系删除!
更多推荐


所有评论(0)