C++11 核心特性深度解析(三):lambda 表达式
·
一、lambda 表达式语法
1.1 基本格式

| 组成部分 | 说明 | 是否可省略 |
|---|---|---|
[capture-list] |
捕捉列表:捕获上下文变量 | ❌ 不可省略 |
(parameters) |
参数列表:同普通函数 | ✅ 无参数可省略 |
-> return_type |
返回值类型:追踪返回类型 | ✅ 可推导时省略 |
{ function_body } |
函数体:实现逻辑 | ❌ 不可省略 |
1.2 语法规则详解
规则 1:捕捉列表不可省略

规则 2:参数列表可省略

规则 3:返回值可省略(编译器推导)

规则 4:函数体不可省略

1.3 完整示例
int main() {
// 最简单的 lambda
auto add1 = [](int x, int y) -> int { return x + y; };
cout << add1(1, 2) << endl; // 输出 3
// 省略参数列表(无参数)
auto func1 = [] {
cout << "hello bit" << endl;
return 0;
};
func1();
// 省略返回值
auto func2 = [](int x, int y) { return x + y; };
// 交换两个变量
int a = 0, b = 1;
auto swap1 = [](int& x, int& y) {
int tmp = x;
x = y;
y = tmp;
};
swap1(a, b);
cout << a << ":" << b << endl; // 输出 1:0
return 0;
}
二、捕捉列表
lambda 表达式中默认只能使用 lambda 函数体和参数中的变量。如果想用外层作用域中的变量,就需要进行捕捉。
2.1 显式捕捉
传值捕捉
int a = 0, b = 1, c = 2, d = 3;
auto func1 = [a, &b] { // a 值捕捉,b 引用捕捉
// a++; // ❌ 错误!值捕捉默认是 const 的,不能修改
b++; // ✅ 正确!引用捕捉可以修改
int ret = a + b;
return ret;
};
cout << func1() << endl; // 输出 2(a=0, b=2)
传引用捕捉
auto func2 = [&a, &b, &c, &d] { // 全部引用捕捉
a++;
b++;
c++;
d++;
return a + b + c + d;
};
func2();
cout << a << " " << b << " " << c << " " << d << endl; // 输出 1 2 3 4
2.2 隐式捕捉
隐式值捕捉(=)
int a = 0, b = 1, c = 2;
auto func2 = [=] { // = 表示隐式值捕捉:用了哪些就捕捉哪些
int ret = a + b + c; // 编译器自动捕捉 a, b, c
return ret;
};
cout << func2() << endl; // 输出 3
隐式引用捕捉(&)
auto func3 = [&] { // & 表示隐式引用捕捉
a++; // 修改外部变量
c++;
d++;
};
func3();
cout << a << " " << b << " " << c << " " << d << endl; // 输出 1 1 3 4
2.3 混合捕捉
语法规则
-
第一个元素必须是
&或= -
&混合捕捉时,后面的变量必须是值捕捉 -
=混合捕捉时,后面的变量必须是引用捕捉

2.4 mutable 关键字
问题:值捕捉默认是 const 的

解决:mutable 取消常量性

重要:
-
mutable相当于去掉 const 属性 -
但修改的是形参副本,不会影响外部变量
-
使用
mutable后,参数列表不可省略(即使参数为空)
2.5 捕捉规则总结
| 捕捉方式 | 语法 | 能否修改外部变量 | 说明 |
|---|---|---|---|
| 显式值捕捉 | [x, y] |
❌ | 拷贝外部变量,默认 const |
| 显式引用捕捉 | [&x, &y] |
✅ | 引用外部变量 |
| 隐式值捕捉 | [=] |
❌ | 自动值捕捉使用的变量 |
| 隐式引用捕捉 | [&] |
✅ | 自动引用捕捉使用的变量 |
| 混合捕捉 | [&, x] |
x❌ 其他✅ | 其他引用,x 值捕捉 |
| 混合捕捉 | [=, &x] |
x✅ 其他❌ | 其他值,x 引用捕捉 |
| mutable | [=]() mutable |
形参可改 | 取消 const,但不影响实参 |
2.6 特殊规则
全局变量和静态变量不需要捕捉

只能捕捉 lambda 位置之前定义的变量

三、lambda 的应用
3.1 替代仿函数
在学习 lambda 之前,可调用对象只有函数指针和仿函数对象:
| 可调用对象 | 优点 | 缺点 |
|---|---|---|
| 函数指针 | 简单 | 类型定义麻烦,无法捕获上下文 |
| 仿函数 | 可捕获状态(成员变量) | 需要定义一个类,代码冗余 |
| lambda | 简洁 + 可捕获状态 | 无 |
仿函数写法(繁琐)
struct ComparePriceLess {
bool operator()(const Goods& gl, const Goods& gr) {
return gl._price < gr._price;
}
};
struct ComparePriceGreater {
bool operator()(const Goods& gl, const Goods& gr) {
return gl._price > gr._price;
}
};
struct CompareEvaluateLess {
bool operator()(const Goods& gl, const Goods& gr) {
return gl._evaluate < gr._evaluate;
}
};
// 使用
sort(v.begin(), v.end(), ComparePriceLess());
sort(v.begin(), v.end(), ComparePriceGreater());
lambda 写法(简洁)
sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
return g1._price < g2._price;
});
sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
return g1._price > g2._price;
});
sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
return g1._evaluate < g2._evaluate;
});
3.2 排序比较器
struct Goods {
string _name; // 名字
double _price; // 价格
int _evaluate; // 评价
Goods(const char* str, double price, int evaluate)
: _name(str), _price(price), _evaluate(evaluate) {}
};
int main() {
vector<Goods> v = {
{"苹果", 2.1, 5},
{"香蕉", 3, 4},
{"橙子", 2.2, 3},
{"菠萝", 1.5, 4}
};
// 按价格升序
sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
return g1._price < g2._price;
});
// 按价格降序
sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
return g1._price > g2._price;
});
// 按评价升序
sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
return g1._evaluate < g2._evaluate;
});
// 按评价降序
sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
return g1._evaluate > g2._evaluate;
});
return 0;
}
3.3 线程执行逻辑
#include <thread>
int main() {
int id = 42;
// lambda 作为线程执行函数
thread t([id] { // 值捕捉 id
cout << "Thread " << id << " is running" << endl;
});
t.join();
return 0;
}
3.4 智能指针定制删除器
#include <memory>
// 自定义删除器:用 lambda 替代函数对象
auto fileDeleter = [](FILE* fp) {
if (fp) {
fclose(fp);
cout << "File closed" << endl;
}
};
int main() {
// unique_ptr 使用 lambda 删除器
unique_ptr<FILE, decltype(fileDeleter)> fp(
fopen("test.txt", "r"),
fileDeleter
);
// shared_ptr 也可以
shared_ptr<FILE> sp(
fopen("test.txt", "r"),
[](FILE* fp) { fclose(fp); }
);
return 0;
}
四、lambda 的原理
4.1 编译器生成的仿函数类
lambda 的原理和范围 for 很像:
编译后从汇编指令层看,压根就没有 lambda 这种东西。
lambda 的底层是仿函数对象,编译器会生成一个对应的仿函数类。
// ========== 仿函数写法 ==========
class Rate {
public:
Rate(double rate) : _rate(rate) {}
double operator()(double money, int year) {
return money * _rate * year;
}
private:
double _rate;
};
// ========== 等价的 lambda 写法 ==========
double rate = 0.49;
auto r2 = [rate](double money, int year) {
return money * rate * year;
};
编译器生成的类(伪代码)
// 编译器为 lambda 生成的类(类名是编译器按规则生成的)
class __lambda_xxx { // 类名保证唯一性
public:
// 构造函数:用捕捉列表初始化成员变量
__lambda_xxx(double rate) : _rate(rate) {}
// operator():参数和返回值来自 lambda 定义
double operator()(double money, int year) const {
return money * _rate * year;
}
private:
double _rate; // 捕捉列表的变量 → 成员变量
};
// 编译器将 lambda 替换为:
// auto r2 = __lambda_xxx(rate);
捕捉列表的本质
| lambda 语法 | 编译器实现 |
|---|---|
[rate] |
double _rate; 成员变量 |
[&rate] |
double& _rate; 成员引用 |
[=] |
自动生成的多个成员变量 |
[&] |
自动生成的多个成员 |
更多推荐

所有评论(0)