Lambda 表达式的完整语法:
cpp
[capture](params) mutable -> return_type { body }
各部分都可以省略,形成不同写法:
1. 最简形式(无捕获、无参数)
cpp
auto f = [] { return 42; };
std::cout << f(); // 输出 42
2. 带参数
cpp
auto add = [](int a, int b) { return a + b; };
std::cout << add(1, 2); // 输出 3
3. 显式指定返回类型
当返回类型无法自动推导,或想明确时:
cpp
// C++11 风格:尾置返回类型
auto f = [](int x) -> double { return x * 1.5; };
// 常见场景:返回复杂类型或条件分支
auto g = [](bool flag) -> std::string {
return flag ? "yes" : "no";
};
4. 捕获外部变量(核心用法)
cpp
int x = 10;
int y = 20;
// [=] 按值捕获所有外部变量
auto f1 = [=] { return x + y; };
// [&] 按引用捕获所有外部变量
auto f2 = [&] { x = 100; y = 200; }; // 可以修改外部变量
f2();
// 现在 x=100, y=200
// 混合捕获:值捕获 x,引用捕获 y
auto f3 = [=, &y] { y = x + 1; };
// 混合捕获:引用捕获 x,值捕获 y
auto f4 = [&, x] { /* y 可修改,x 只读 */ };
// 只捕获特定变量
auto f5 = [x] { return x; }; // 值捕获 x
auto f6 = [&y] { y = 99; }; // 引用捕获 y
auto f7 = [x, &y] { y = x + 1; }; // 混合
混合捕获详解
[=, &y] --- 默认值捕获,y 单独引用捕获
cpp
int x = 10;
int y = 20;
int z = 30;
// [=] 默认按值捕获所有外部变量
// 但 &y 单独指定 y 按引用捕获
auto f = [=, &y] {
// x、z 是值捕获 → 只读副本,不能修改
// y 是引用捕获 → 可以修改原变量
// int tmp = x; // ✅ 可以读 x
// x = 100; // ❌ 编译错误:x 是 const 副本
y = x + z; // ✅ 可以修改 y(引用捕获)
// z = 50; // ❌ 编译错误:z 是 const 副本
};
f();
// 执行后:x=10, y=40(被修改了), z=30
记忆规则 :[=, &y] = "默认全值,y 特殊照顾按引用"
[&, x] --- 默认引用捕获,x 单独值捕获
cpp
int x = 10;
int y = 20;
int z = 30;
// [&] 默认按引用捕获所有外部变量
// 但 x 单独指定按值捕获
auto f = [&, x] {
// y、z 是引用捕获 → 可读可写
// x 是值捕获 → 只读副本
y = 100; // ✅ 可以修改 y(引用捕获)
z = 200; // ✅ 可以修改 z(引用捕获)
// int tmp = x; // ✅ 可以读 x
// x = 50; // ❌ 编译错误:x 是 const 副本
};
f();
// 执行后:x=10(没变), y=100, z=200
记忆规则 :[&, x] = "默认全引用,x 特殊照顾按值"
5. mutable 关键字(修改值捕获的副本)
默认情况下,值捕获的变量在 lambda 内是 const 的:
cpp
int x = 10;
// 错误:不能修改值捕获的副本
// auto f = [x] { x++; }; // 编译失败
// 正确:加 mutable 允许修改副本(不影响原变量)
auto f = [x]() mutable {
x++; // 修改的是副本
return x;
};
f(); // 返回 11
f(); // 返回 12(副本被保留了)
std::cout << x; // 原变量仍是 10
6. 初始化捕获(C++14)
在捕获列表里直接初始化:
cpp
auto f1 = [x = 10] { return x; }; // 捕获时初始化
auto f2 = [x = std::move(ptr)] { /* ... */ }; // 移动捕获
int a = 5;
auto f3 = [x = a + 1] { return x; }; // 表达式初始化
7. 泛型 lambda(C++14)
参数用 auto,实现类似模板的效果:
cpp
// 泛型 lambda,可接受任意类型
auto add = [](auto a, auto b) { return a + b; };
add(1, 2); // int + int
add(1.5, 2.5); // double + double
add(std::string("a"), std::string("b")); // string + string
8. 无捕获 lambda 可转换为函数指针
cpp
// 无捕获的 lambda 可以隐式转换为函数指针
int (*fp)(int) = [](int x) { return x * 2; };
std::cout << fp(5); // 输出 10
// 有捕获的 lambda 不能这样做
int y = 10;
// int (*fp2)(int) = [y](int x) { return x + y; }; // 编译失败
9. 实际场景示例
作为回调函数
cpp
std::vector<int> v = {1, 2, 3, 4, 5};
// std::sort 降序排序
std::sort(v.begin(), v.end(), [](int a, int b) {
return a > b;
});
// std::find_if 查找
auto it = std::find_if(v.begin(), v.end(), [](int x) {
return x > 3;
});
作为 std::function 存储
cpp
std::function<int(int, int)> f = [](int a, int b) { return a + b; };
用于延迟执行
cpp
int threshold = 5;
auto is_large = [threshold](int x) { return x > threshold; };
// 稍后使用
for (int x : {3, 7, 2, 9}) {
if (is_large(x)) std::cout << x << " ";
}
速查表
| 写法 | 含义 |
|---|---|
[] |
不捕获任何外部变量 |
[=] |
按值捕获所有外部变量 |
[&] |
按引用捕获所有外部变量 |
[x] |
只值捕获 x |
[&x] |
只引用捕获 x |
[=, &x] |
值捕获所有,但 x 按引用 |
[&, x] |
引用捕获所有,但 x 按值 |
[x, &y] |
x 按值,y 按引用 |
[x = expr] |
初始化捕获(C++14) |
[...]= |
包展开,按值捕获(C++20) |
[...&] |
包展开,按引用捕获(C++20) |