一、引言
C++11中引入的lambda表达式(也称为匿名函数或lambda函数)提供了一种方便且灵活的方式来定义和使用小的匿名函数对象。这些lambda表达式在编写回调函数、操作容器的算法中、或者在需要快速定义和传递一个函数逻辑给另一个函数时特别有用。
二、基本语法
[capture](parameters) mutable -> return_type {
// 函数体
}
- capture:对lambda函数外部变量的捕获方式:
表示方式 | 说明 |
[ ] | 不捕获任何外部变量 |
[=] | 以值传递的方式捕获全部外部变量 |
[&] | 以引用传递的方式捕获全部外部变量 |
[&x, y] | x以引用传递的方式捕获,y以传值的方式捕获 |
- parameters:函数的参数列表
- mutable:是否可以修改以值传递的外部变量,加上mutable表示可以修改,否则不能修改
- return_type:函数的返回类型,省略时,返回类型就是函数内return语句返回值的类型。
说明:全局变量会自动进行引用捕获。
三、外部变量的捕获
1. 不捕获任何外部变量
int main(){
auto fun = [](int a, int b)->int{
return a + b;
};
int sum = fun(1, 2);
cout << sum << endl; // 输出3
return 0;
}
2. 访问全局变量
int x = 10; // 全局变量
int main(){
auto fun = [](){
++x; // 自动捕获全局变量 x
};
cout << x << endl; // 输出10
fun();
cout << x << endl; // 输出11
return 0;
}
3. 传值捕获所有外部变量
int main(){
int x = 10;
int y = 20;
auto fun = [=]()->int{
// x++; //不可以修改x的值,x在lambda内是const的
return x + y; // x得到30
};
int sum = fun();
cout << sum << endl;
return 0;
}
输出内容:
从输出的地址可以知道,lambda函数内的变量x与函数外的变量x不是同一个变量,只是用外部x变量的值初始化了函数内的x变量(相当于传值的形参)。并且不能修改x的值,因为x是const的。如果想要修改x的值,可以使用mutable关键字修饰lambda函数。
4. 以引用的方式捕获所有的外部变量
int main(){
int x = 10;
int y = 20;
cout << (&x) << endl;
auto fun = [&]()->int{
x++; //以引用方式捕获的变量可以修改其值
cout << (&x) << endl;
return x + y;
};
int sum = fun();
cout << sum << endl;
return 0;
}
输出内容:
从输出的地址可以知道,lambda函数内的变量x与函数外的变量x是同一个变量(地址相同)。
5. 混合捕获
int main(){
int x = 10;
int y = 20;
cout << (&x) << endl;
auto fun = [&x, y]()mutable{
x++; // 可以修改x的值,修改的是函数外的x变量
y++; // y以传值捕获,因为函数声明为mutable,所有y可以修改,修改的是lambda内部的y
cout << (&x) << endl;
return x + y;
};
int sum = fun();
cout << sum << endl;
cout << "x = " << x << ", y = " << y << endl;
return 0;
}
输出内容:
x以引用传递,y以值传递,所以在lambda函数内修改的x是函数外的x,而y则是lambda函数内的y,与函数外的y不是同一个变量。
四、参数示例
lambda函数的参数和普通函数是一样的,可以有传值、传地址和传引用几种方式。
1. 传值
int main(){
int x = 10;
int y = 20;
cout << (&x) << endl;
auto fun = [](int x, int y){
x++; // 可以修改形参x的值
y++; // 可以修改形参y的值
cout << (&x) << endl;
return x + y;
};
int sum = fun(x, y);
cout << sum << endl;
// lambda函数外的x和y没有被修改
cout << "x = " << x << ", y = " << y << endl;
return 0;
}
2. 传地址
int main(){
int x = 10;
int y = 20;
auto fun = [](int *x, int *y){
(*x)++;
(*y)++;
return (*x) + (*y);
};
int sum = fun(&x, &y);
cout << sum << endl;
// x = 11, y = 21
cout << "x = " << x << ", y = " << y << endl;
return 0;
}
3. 传引用
int main(){
int x = 10;
int y = 20;
auto fun = [](int &x, int &y){
x++;
y++;
return x + y;
};
int sum = fun(x, y);
cout << sum << endl;
// x = 11, y = 21
cout << "x = " << x << ", y = " << y << endl;
return 0;
}
六、常用场合
1. 临时函数
// lambda表达式
#include <iostream>
#include <cstdlib>
using namespace std;
int main() {
int arr[]{4,1,8,5,2};
qsort(arr, sizeof(arr)/sizeof(arr[0]), sizeof(arr[0]),
[](const void *p1, const void *p2){
int a = *((int*)p1);
int b = *((int*)p2);
return a == b ? 0 : (a < b ? 1 : -1);
});
for (int i: arr){
cout << i << " ";
} // 降序排列,输出8 5 4 2 1
return 0;
}
2. STL算法中
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5};
// 使用lambda表达式对vector中的每个元素加1
std::for_each(numbers.begin(), numbers.end(), [](int& n) { n += 1; });
// 打印结果
for(int n : numbers) {
std::cout << n << ' ';
}
std::cout << '\n';
return 0;
}
七、注意事项
Lambda表达式产生的对象类型是唯一的匿名非联合非聚合类类型,称为闭包类型。
捕获的变量(如果是引用捕获)在lambda函数体之外的生命周期结束时,引用可能变为悬空引用,使用时需要特别注意。
Lambda表达式中的this指针在捕获列表中自动处理,如果使用[&]或[=]捕获方式,则this指针会被捕获。如果要显式捕获this,可以在捕获列表中包含*this或this(视具体需求而定)。
八、小结
C++11中的lambda表达式是C++编程中一个非常强大的特性,极大地增强了代码的灵活性和表达能力。同时增强了函数式编程的能力。
附:c++11新增的其他性