在C++中,lambda表达式是一种匿名函数对象,用于创建临时的、短小的函数。它特别适合作为算法(如sort
、find_if
)的谓词或回调函数。下面详细介绍其语法、捕获列表、参数列表和返回类型。
一、基本语法
[capture list](parameter list) -> return type {function body
}
各部分说明:
-
[capture list]
- 捕获外部变量,使lambda内部可以访问。
- 示例:
int x = 10; auto add_x = [x](int y) { return x + y; }; // 捕获x的值
-
(parameter list)
- 与普通函数的参数列表类似,但不能有默认参数。
- 示例:
auto sum = [](int a, int b) { return a + b; }; // 接受两个int参数
-
-> return type
- 返回类型可以省略,编译器会自动推导。
- 示例:
auto square = [](int x) -> double { return x * x; }; // 显式指定返回类型为double
-
{ function body }
- 函数体,可以使用捕获的变量和传入的参数。
二、捕获列表(Capture List)
捕获列表用于指定lambda如何访问外部变量,有以下几种方式:
1. 值捕获(By Value)
int x = 5;
auto lambda = [x]() { return x * 2; }; // 捕获x的值
- 特点:lambda内部使用的是x的副本,修改lambda内部的x不会影响外部变量。
2. 引用捕获(By Reference)
int x = 5;
auto lambda = [&x]() { x *= 2; }; // 捕获x的引用
lambda(); // 执行后,外部的x变为10
- 特点:lambda内部直接使用外部变量的引用,修改会影响外部变量。
3. 隐式捕获
int x = 1, y = 2;
auto sum = [=]() { return x + y; }; // 以值方式捕获所有外部变量
auto product = [&]() { return x * y; }; // 以引用方式捕获所有外部变量
[=]
:值捕获所有外部变量。[&]
:引用捕获所有外部变量。
4. 混合捕获
int x = 1, y = 2;
auto lambda = [&, x]() { y += x; }; // 引用捕获y,值捕获x
- 规则:捕获列表中,
[&, var]
表示除var
外以引用捕获,[=, &var]
表示除var
外以值捕获。
三、参数列表和返回类型
1. 参数列表
与普通函数类似,但不能有默认参数:
auto add = [](int a, int b) { return a + b; }; // 两个int参数
auto identity = [](auto x) { return x; }; // C++14起支持泛型lambda
2. 返回类型
- 自动推导(推荐):
auto divide = [](double a, double b) { return a / b; }; // 返回类型为double
- 显式指定(复杂情况):
auto conditional = [](int x) -> double {return x > 0 ? x : 0.5; // 返回类型可能是int或double,需显式指定为double };
四、mutable关键字
默认情况下,值捕获的变量在lambda内部是只读的。使用mutable
可以修改值捕获的变量:
int x = 10;
auto lambda = [x]() mutable {x += 5; // 允许修改值捕获的x的副本return x;
};
std::cout << lambda(); // 输出15
std::cout << x; // 外部的x仍为10
五、应用场景
1. 作为算法的谓词
std::vector<int> nums = {3, 1, 4, 1, 5};
std::sort(nums.begin(), nums.end(), [](int a, int b) { return a > b; }); // 降序排序
2. 回调函数
std::function<void()> callback;
{int x = 100;callback = [&x]() { std::cout << x; }; // 危险!引用捕获局部变量x
} // x已销毁,调用callback会导致未定义行为
3. 延迟执行
auto delayed_sum = [](int a, int b) {return [=]() { return a + b; }; // 返回一个新的lambda
};
auto result = delayed_sum(3, 4);
std::cout << result(); // 输出7
六、注意事项
-
捕获生命周期:
引用捕获的变量必须在lambda执行时仍然有效。避免捕获局部变量的引用,除非确保lambda会在局部变量销毁前执行。 -
性能考虑:
- 值捕获会复制变量,大型对象建议使用引用捕获。
- 空捕获列表的lambda可以隐式转换为函数指针。
-
泛型lambda(C++14+):
使用auto
作为参数类型,创建类似模板的lambda:auto print = [](const auto& value) { std::cout << value << "\n"; };
七、与LeetCode 179的关联
在LeetCode 179中,lambda表达式用于定义自定义排序规则:
sort(strs.begin(), strs.end(), [](const string& a, const string& b) {return a + b > b + a; // 比较拼接后的字符串大小
});
这里:
- 捕获列表为空:不需要访问外部变量。
- 参数为两个字符串:表示待比较的数字的字符串形式。
- 返回布尔值:决定排序顺序。
总结
C++的lambda表达式是一种灵活、高效的创建匿名函数的方式,特别适合在需要临时函数对象的场景中使用。掌握其语法和捕获机制,可以编写出更简洁、更具表现力的代码。