1. Lambda表达式深度解析
1.1 为什么需要Lambda表达式
在C++98标准中,我们经常遇到需要传递函数对象的情况。以商品排序为例,我们需要为每种排序规则单独定义一个仿函数类:
cpp复制struct ComparePriceLess {
bool operator()(const Goods& gl, const Goods& gr) {
return gl._price < gr._price;
}
};
这种实现方式存在几个明显问题:
- 代码冗余:每个比较规则都需要定义完整的类结构
- 命名负担:需要为每个比较规则想不同的类名
- 可读性差:业务逻辑被分散到多个类定义中
C++11引入Lambda表达式后,同样的功能可以这样实现:
cpp复制sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
return g1._price < g2._price;
});
实际工程经验:在需要频繁定义简单函数对象的场景(如STL算法回调、事件处理等),Lambda可以减少90%以上的样板代码。
1.2 Lambda表达式完整语法剖析
Lambda表达式的标准语法如下:
cpp复制[capture-list] (parameters) mutable -> return-type { body }
1.2.1 捕获列表详解
捕获列表决定了外部变量如何被Lambda内部访问:
- 值捕获
[var]:创建时拷贝变量值 - 引用捕获
[&var]:直接引用外部变量 - 隐式捕获:
[=]:所有变量值捕获[&]:所有变量引用捕获
- 混合捕获
[=, &x]:x引用捕获,其余值捕获
cpp复制int a = 1, b = 2;
auto lambda = [a, &b](int x) mutable {
a++; // 需要mutable才能修改值捕获的变量
b++; // 引用捕获可直接修改
return a + b + x;
};
注意事项:
- 避免在Lambda生命周期超过捕获变量时使用引用捕获
- 值捕获的大型对象可能带来性能问题
- 默认捕获([=]或[&])可能导致意外的变量捕获
1.2.2 mutable关键字的本质
mutable允许修改值捕获的变量,其底层原理是移除了捕获变量的const限定:
cpp复制// 无mutable
auto l1 = [x](int y) { /* x是const的 */ };
// 有mutable
auto l2 = [x](int y) mutable { /* x可修改 */ };
1.2.3 返回类型推导规则
当Lambda体只包含一个return语句时,返回类型可自动推导:
cpp复制auto l1 = [](int x) { return x * 1.5; }; // 推导为double
复杂情况需要显式指定返回类型:
cpp复制auto l2 = [](int x) -> double {
if(x > 0) return x *
