lamda表达式
C++ 中的 Lambda 表达式(也常被称为匿名函数或Lambda 函数:说人话就是没有名字的函数)是一种用于快速定义匿名函数对象的强大特性,自 C++11 起被引入。它的核心价值在于能够就地定义简短的、一次性的函数逻辑,特别适合作为回调函数传递给标准库算法(如 std::sort, std::for_each),或在异步编程、多线程等场景中使用。
下面这个表格能帮你快速理解 Lambda 表达式的主要组成部分。
|
捕获列表 [] |
必需 |
定义 Lambda 如何获取其外部作用域中的变量。例如,[x]按值捕获 x,[&y]按引用捕获 y。 |
|
参数列表 () |
可选 |
和普通函数的参数列表一样,定义 Lambda 可以接受哪些参数。可以为空 ()。 |
|
可变规范 mutable |
可选 |
允许 Lambda 修改其按值捕获的变量的副本(注意:不影响原始变量)。通常按值捕获的变量在 Lambda 内是只读的,除非使用 mutable。 |
|
返回类型 -> type |
可选 |
显式指定 Lambda 的返回类型。大多数情况下,编译器可以自动推断,可省略。 |
|
函数体 {} |
必需 |
包含 Lambda 要执行的实际代码。 |
💡 捕获列表详解
捕获列表是 Lambda 表达式的关键特性,它决定了 Lambda 函数体内能够访问和操作哪些来自外部作用域的变量。理解不同的捕获方式至关重要。
|
不捕获任何变量 |
[] |
Lambda 体内不能使用任何外部变量(全局变量等具有静态存储期的变量除外)。 |
|
按值捕获 |
[x] |
创建外部变量 x的一个副本供 Lambda 内部使用。在 Lambda 内部修改这个副本不影响外部的原始变量 x。 |
|
按引用捕获 |
[&y] |
Lambda 内部直接使用外部变量 y的引用。在 Lambda 内部修改 y会直接影响外部的原始变量。 |
|
隐式捕获(捕获所有) |
[=]或 [&] |
[=]:Lambda 体内使用的所有外部变量都按值捕获。[&]:Lambda 体内使用的所有外部变量都按引用捕获。 |
|
混合捕获 |
[=, &z]或 [&, x] |
可以组合使用。例如 [=, &z]表示除变量 z按引用捕获外,其他使用的变量都按值捕获。 |
重要提醒:使用按引用捕获(特别是捕获局部变量)时,必须确保 Lambda 被调用时,所引用的变量仍然有效(即未被销毁)。否则会导致未定义行为,这是常见的错误来源。
自定义排序
在一些时候,只是使用c++自带的sort函数并不能满足我们对排序的需求,这时候就需要用到利用自定义比较函数了;
实现自定义比较函数有两种方法,一种是先把比较函数cmp定义出来,再在sort中调用:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
// 定义比较函数:降序排列
bool cmp(int a, int b) {
return a > b; // 当a>b时返回true,表示a应该排在b前面
}
int main() {
vector<int> nums = {3, 1, 4, 1, 5, 9, 2, 6};
// 使用自定义比较函数排序
sort(nums.begin(), nums.end(), cmp);
for (int num : nums) {
cout << num << " "; // 输出:9 6 5 4 3 2 1 1
}
return 0;
}
另一种就是在sort中直接定义lamda函数,进行排序:
#include <algorithm>
#include <vector>
#include <string>
struct Student {
std::string name;
int score;
int age; // 假设我们增加一个年龄字段
};
int main() {
std::vector<Student> students = {{"Alice", 85, 20}, {"Bob", 90, 19}, {"Charlie", 85, 21}};
// 使用Lambda表达式:按成绩降序,成绩相同时按年龄升序
std::sort(students.begin(), students.end(), [](const Student& a, const Student& b) {
if (a.score != b.score) {
return a.score > b.score; // 首先,按成绩降序
}
return a.age < b.age; // 成绩相同,则按年龄升序
});
return 0;
}
无论采用哪种方法,关键在于正确编写比较函数。它需要接受两个参数(通常是常量引用,以避免拷贝开销,对于结构体这种内存开销大的比赛时建议用引用,不然小心超时),并返回一个布尔值:
-
返回 true:表示第一个参数应该排在第二个参数之前。
-
返回 false:表示第一个参数不应排在第二个参数之前。
基于这个规则:
-
若希望实现升序排序(从小到大),则当 a < b时返回 true。
-
若希望实现降序排序(从大到小),则当 a > b时返回 true。
⚠️ 重要注意事项
严格弱序:自定义的比较规则必须满足严格弱序关系。这意味着它不能产生循环逻辑,例如,如果 cmp(a, b)为 true,则 cmp(b, a)必须为 false。违反此规则会导致未定义行为。
效率考虑:在比较函数中,应尽量使用常量引用(const T&)来传递参数,特别是当结构体较大时,这样可以避免不必要的值拷贝,提升效率。
容器适配器:请注意,std::set、std::map、std::priority_queue等容器有它们自己的模板参数来定义排序规则,通常要求重载 <运算符或提供单独的仿函数类。



