C++中的lambda表达式是一种可以定义在语句或表达式内部的匿名函数对象,它不需要单独的函数名,能够直接 inline 到代码中,非常适合编写短小的回调函数或者临时逻辑。

lambda表达式的基本语法
C++ lambda表达式的完整语法结构如下:
[capture_list](parameter_list) mutable noexcept -> return_type {
// 函数体
}
其中各个部分的含义如下:
- capture_list(捕获列表):用来捕获外部作用域的变量,是lambda表达式和普通函数最大的区别之一,这部分可以为空。
- parameter_list(参数列表):和普通函数的参数列表一致,如果没有参数可以省略括号。
- mutable:可选关键字,默认情况下lambda捕获的变量是只读的,加上mutable可以让捕获的变量在lambda内部被修改。
- noexcept:可选关键字,标记lambda不会抛出异常。
- return_type(返回类型):可以省略,编译器会自动推导返回类型,如果需要显式指定则加上->返回类型。
- 函数体:和普通函数的函数体一致,写具体的执行逻辑。
捕获列表的常见用法
捕获列表决定了lambda可以访问哪些外部变量,以及是按值还是按引用访问,常见的捕获方式有:
| 捕获方式 | 含义 |
|---|---|
[] | 不捕获任何外部变量 |
[x] | 按值捕获变量x,lambda内部x是只读的副本 |
[&x] | 按引用捕获变量x,lambda内部修改x会影响外部的x |
[=] | 按值捕获所有外部自动变量 |
[&] | 按引用捕获所有外部自动变量 |
[=, &x] | 除了x按引用捕获,其他所有变量按值捕获 |
[&, x] | 除了x按值捕获,其他所有变量按引用捕获 |
下面是一个捕获列表的使用示例:
#include <iostream>
int main() {
int a = 10;
int b = 20;
// 按值捕获a,按引用捕获b
auto lambda1 = [a, &b]() {
// a++; // 错误,按值捕获的变量默认只读
b++; // 正确,按引用捕获可以修改
std::cout << "lambda内部 a:" << a << " b:" << b << std::endl;
};
lambda1();
std::cout << "外部 a:" << a << " b:" << b << std::endl;
// 加上mutable后可以修改按值捕获的变量
auto lambda2 = [a]() mutable {
a++;
std::cout << "mutable lambda内部 a:" << a << std::endl;
};
lambda2();
std::cout << "外部 a 依然不变:" << a << std::endl;
return 0;
}
lambda表达式的常见实践场景
配合STL算法使用
lambda最常见的用途是作为STL算法的回调函数,比如std::sort、std::for_each等,避免单独定义函数对象,让代码更紧凑。
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> nums = {3, 1, 4, 1, 5, 9, 2, 6};
// 使用lambda作为排序的比较规则,按降序排序
std::sort(nums.begin(), nums.end(), [](int x, int y) {
return x > y;
});
// 使用lambda遍历输出元素
std::for_each(nums.begin(), nums.end(), [](int num) {
std::cout << num << " ";
});
std::cout << std::endl;
return 0;
}
作为回调函数使用
在事件处理、异步操作等场景中,lambda可以直接作为回调函数传入,不需要额外定义函数。
#include <iostream>
#include <functional>
// 模拟一个异步操作,完成后执行回调
void async_task(std::function<void(int)> callback) {
// 模拟任务执行
int result = 100;
// 执行回调
callback(result);
}
int main() {
// 直接传入lambda作为回调
async_task([](int res) {
std::cout << "异步任务结果:" << res << std::endl;
});
return 0;
}
lambda和普通函数、函数对象的区别
- 和普通函数相比,lambda可以捕获外部变量,更灵活,适合编写短小的临时逻辑,不需要额外的函数定义。
- 和函数对象(重载了
operator()的类)相比,lambda的语法更简洁,编译器会自动生成对应的函数对象类,不需要手动定义类。 - lambda的类型是编译器自动生成的匿名类型,无法直接写出类型名,通常配合
auto或者std::function使用。
注意事项
- 按引用捕获的时候要注意变量的生命周期,避免lambda执行时引用的变量已经被销毁,导致悬垂引用。
- 如果lambda不需要捕获任何变量,尽量使用
[]空捕获列表,避免不必要的捕获。 - lambda的返回类型可以省略,编译器会自动推导,但是如果函数体有多个return语句返回不同类型,就需要显式指定返回类型。