C++中lambda的介绍和简单使用。
构成
C++11下lambda表达式完全体的构成:
[ captures ] ( params ) specifiers exception attr -> ret { body }
其中params和ret可以省略,省略返回值类型相当于返回auto类型,省略(params)相当于lambda函数不接受参数输入,对应以下几种变体:
- [ captures ] ( params ) -> ret { body }
- [ captures ] ( params ) { body }
- [ captures ] { body }
captures
支持值捕获、引用捕获和隐式捕获。
值捕获和引用捕获
在变量前使用前缀=来表示值捕获,&表示引用捕获。变量在captures列表只能出现一次,当变量被一种方式隐式捕获时,显示捕获只能将其声明为另一种捕获方式。
【1】中的例子:
// 默认引用捕获
struct S2 { void f(int i); };
void S2::f(int i)
{
[&]{}; // OK: by-reference capture default
[&, i]{}; // OK: by-reference capture, except i is captured by copy
[&, &i] {}; // Error: by-reference capture when by-reference is the default
[&, this] {}; // OK, equivalent to [&]
[&, this, i]{}; // OK, equivalent to [&, i]
}
// 默认值捕获
struct S2 { void f(int i); };
void S2::f(int i)
{
[=]{}; // OK: by-copy capture default
[=, &i]{}; // OK: by-copy capture, except i is captured by reference
[=, *this]{}; // until C++17: Error: invalid syntax
// since c++17: OK: captures the enclosing S2 by copy
[=, this] {}; // until C++20: Error: this when = is the default
// since C++20: OK, same as [=]
}
隐式捕获
上面的例子中可以看到,当捕获列表的首项为=及&时会按相应的捕获方式捕获所用的变量和this下的成员变量。另外lambda表达式可以不捕获而使用或读取一些变量,比如全局变量、静态局部变量等,具体类型可以查看参考[1]。
#include <iostream>
using namespace std;
int i = 10;
int main()
{
static int j = 1;
auto f = []() {cout <<"i:"<< i <<"\tj:"<< j; };
f();
}
// out:
// i:10 j:1
params
和函数参数差不多,在C++14后不支持指定参数默认值且支持用auto声明参数。
参数名与变量名相同会隐藏所捕获的变量。
ret
返回值类型,可省略。省略后要注意不同分支下返回值类型要保持一致。
body
函数体。当变量为值捕获时,要在lambda表达式的parameter list(不可省略) 和 return type(省略或"->ret"形式)之间指定说明符为mutable才能修改变量的值,但仍是值引用。
int i = 0;
auto f = [i]() mutable {return ++i; };
cout << "i:" << i << "\tf():" << f();
// out:
// i:0 f():1
例子
在一些需要输入函数的时候就可以用lambda生成匿名函数传入,比如std中的sort、for_each等函数。
int main()
{
using namespace std;
vector<int> nums = { 1,2,3,4,5,6,7 };
// 使用lambda和for_each定义一个函数用于输出vector
auto print_vec = [](const vector<int> vec) {
for_each(vec.begin(), vec.end(), [](int i) {cout << i << '\t'; });
};
print_vec(nums);
cout << endl;
// 引用方式修改值
for_each(nums.begin(), nums.end(), [](int& i) { i -= 4; });
print_vec(nums);
cout << endl;
// sort自定义排序
sort(nums.begin(), nums.end(), [](int a, int b) -> bool { return abs(a) < abs(b); });
print_vec(nums);
cout << endl;
}
// out:
// 1 2 3 4 5 6 7
// -3 -2 -1 0 1 2 3
// 0 -1 1 -2 2 -3 3