具体例子见LeetCode第133场周赛
在LeetCode第133场周赛打完铁(做对了一个==),看神犇们的解答时发现了在sort
里有一块没见过的神操作
sort(costs.begin(),costs.end(),[](vector<int> &a,vector<int> &b){
return a[0] - a[1] < b[0] - b[1];
});
仔细一看又有点眼熟,查了查原来就是平时程序中那一大段取消cin,cout
连接的Lambda
表达式1,查了一下详细用法,这里记录下来
//就是这个
static const auto io_sync_off = []() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
return nullptr;
}();
捕获子句部分基本参考2 ,其余根据MSDN
个人整理3 ,刚开始理解难免有错误欢迎指正
Lambda表达式是C++11引入的特性,是一种描述函数对象的机制,它的主要应用是描述某些具有简单行为的函数。Lambda也可以称为匿名函数。
Lambda 表达式的各部分
Lambda表达式完整的声明格式如下:
[capture list] (parameter list) mutable exception -> return type { function body }
各项具体含义:
- capture list:捕获外部变量列表
- parameter list:参数列表
- mutable:用来说用是否可以修改捕获的变量
- exception:异常设定
- return type:返回类型
- function body:函数体
捕获子句
Lambda表达式可以访问或捕获周边范围变量。 Lambda 以 capture 子句开头,它指定哪些变量被捕获,以及捕获是通过值或引用。
1.空
空 capture 子句 [ ]
指示 lambda 表达式的主体不访问封闭范围中的变量。
2.值捕获
传递值,相当于以复制的形式传入
int a = 123;
auto print = [a]() {
cout << a << endl;
};
a = 456;
print(); //输出123
3.引用捕获
也就是平时所说的传引用
int a = 123;
auto print = [&a]() {
cout << a << endl;
};
a = 456;
print(); //输出456
4.隐式捕获
上面的值捕获和引用捕获都需要我们在捕获列表中显示列出Lambda表达式中使用的外部变量。除此之外,我们还可以让编译器根据函数体中的代码来推断需要捕获哪些变量,这种方式称之为隐式捕获。隐式捕获有两种方式,分别是 [=]
和 [&]
。[=]
表示以值捕获的方式捕获外部变量, [&]
表示以引用捕获的方式捕获外部变量。
值捕获
int a = 123;
auto print = [=]() {
cout << a << endl;
};
a = 456;
print(); //123
引用捕获
int a = 123;
auto print = [&]() {
cout << a << endl;
};
a = 456;
print(); //456
5、混合方式
多种捕获方式可以共存
a
以引用捕获,其他以值捕获,注意一定要 = 在前,也就是先确定所有,再特殊个别
int a = 123;
int b = 456;
auto print = [=, &a]() {
cout << a << " " << b << endl;
};
a = 789;
print(); //789 456
b
以值捕获,其他以引用捕获
int a = 123;
int b = 456;
auto print = [&, b]() {
cout << a << " " << b << endl;
};
a = 789;
print(); //789 456
参数列表
除了捕获变量,lambda 还可接受输入参数。
1.通过传递参数
auto print = [](int a, int b) {
cout << a << " " << b << endl;
return a + b;
};
cout << print(1, 2); //输出1 2\n 3
2.直接赋值调用
auto print = [](int a, int b) {
cout << a << " " << b << endl;
return a + b;
}(1, 2); //输出1 2\n 3
cout << print; //这里的print就相当于一个int变量了,不能加括号
并且在C++ 14,如果参数类型是泛型,则可以使用 auto 关键字作为类型说明符。
lambda 表达式可以将另一个 lambda 表达式作为其自变量。(都是坑,待填)
可变规范
使用mutable关键字可以改变以值捕获方式传进的变量,但是不会改变变量本身的值
int a = 666;
auto print = [=]() mutable {
a = 999; //可以改变,但不会改变a本身的值
cout << a << endl;
};
print(); // 999
cout << a; // 666
异常规范
你可以使用 noexcept
异常规范来指示 lambda 表达式不会引发任何异常(不会)
[]() noexcept { throw 5; }();
返回类型
编译器将自动推导 Lambda 表达式的返回类型:
1.如果函数体中存在return语句,编译器将从返回表达式的类型推导返回类型
2.如果函数体中没有return语句,则返回值为void类型
3.lambda 表达式可以生成另一个 lambda 表达式作为其返回值
返回int
型
auto fun = [](int a) {
return a;
};
当然也不是能推断出所有的返回类型,错误的例子
auto fun = [] {
return {1, 2};
};
//报错a brace-enclosed list does not provide a return type for this lambda
//大括号括起来的列表不提供此lambda的返回类型
解决方法
//返回一个具体的类型
auto fun = [] {
return make_pair(1, 2);
};
//或规定其返回类型,注意加上小括号
auto fun = []() -> pair<int, int> {
return {1, 2};
};
函数体
其实上面的例子并没有体现出lambda
表达式的特殊性,之所以叫匿名函数,就是可以不规定其名称,但是其可以像函数一样运行
cout << [](int a, int b) {
cout << a << " " << b << endl;
return a + b;
}(1, 2)
<< endl; //输出1 2\n 3
也可以捕获变量进行操作:引用隐式捕获m
,值显示捕获n
,赋值a = 4
,并且n
可变
int n = 0, m = 0;
[&, n](int a) mutable {
m = ++n + a;
}(4);
cout << n << " " << m << endl; //输出0 5
具体作用
目前来说就sort
函数下可以利用lambda
表达式来减少代码量
比如周赛题中的排序
bool cmp(vector<int> &a, vector<int> &b)
{
return a[0] - a[1] < b[0] - b[1];
}
sort(costs.begin(), costs.end(), cmp);
就可以用lambda
表达式直接代替
sort(costs.begin(), costs.end(), [](vector<int> &a, vector<int> &b){
return a[0] - a[1] < b[0] - b[1];
});