在调用一些函数的时需要将另一个函数作为参数传入,这些函数只能有一个参数(一元谓词)或两个参数(二元谓词),但是有的时候我们需要更多的参数传入这个函数,这时候我们就可以使用lambda表达式来避免这个问题。
目录
一、lambda表达式
一个lambda表达式表示一个可调用的代码单元,我们可以将其理解为一个没有函数名的内联函数。
参数列表和返回类型是可忽略的,但是捕获列表和函数体不可忽略。
int num = 10;
auto n = [num] {return num; };//注意{ }内是一个函数,所以需要加上;
捕获列表可以捕获lambda表达式所在函数内部的变量 ,此时lambda表达式捕获了上面num的值,并将num作为返回值使得n的值等于num。
vector<int> v{ 3,1,4,6,2,2 };
sort(v.begin(), v.end(), [](int a, int b) {return a < b; });
所需要的a,b在函数中不存在,而是从由sort函数在v中传过去,所以用参数列表而不是捕获列表。
二、捕获
在捕获迭代器/指针或是引用捕获得时候,需要注意捕获对象是存在的。
1.值捕获
与传值拷贝类似,都是对变量进行拷贝,但是与其不同的是,捕获得变量是在lambda创建时拷贝,而非调用时拷贝,因此之后的修改并不会影响到lambda内部对应的值。
int a = 10;
auto n = [a] { return a; };
a++;
cout<<n()<<endl;//打印出来的值是10
需要注意的是值捕获过来的变量是不能修改的,即被const修饰,如果需要修改就得加mutable。
int x = 10;
auto sum = [x](int a) mutable { x *= 2; return a + x; };
cout << sum <<endl;
2.引用捕获
函数体使用该对象是,实际绑定的是所引用的对象,引用对象被修改,lambda对象也会被修改。
int b = 20;
auto m = [&b] { return b; };
b++;
cout << m() << endl;//打印出来的值是21
3.隐式捕获
[=] 采用值捕获得方式进行捕获
[&] 采用引用捕获得方式进行捕获
除了我们指定捕获对象进行捕获之外,还可以通过隐式捕获让编译器推断捕获列表。
int a = 10;
auto n = [=] { return a; };
a++;
cout << n()<<endl;//打印的值为10
int b = 20;
auto m = [&] {return b; };
b++;
cout << m() << endl;//打印值为21
显式捕获和引用捕获可以混用,但第一个元素必须是=或&
auto k1 = [=, &b] {cout << a << b << endl; };
auto k2 = [&, a] {cout << a << b << endl; };
4.可变lambda
由于值捕获是对捕获对象的拷贝,该拷贝被const修饰,不能直接进行修改,需要在参数列表后加mutable才能进行修改。
auto f = [a]()mutable {return ++a; };
引用捕获可以直接对对象进行修改
auto f = [&a] {return ++a; };
三、指定返回类型
auto f2 = [](int a) {a < 0 ? -a : a; };//只有一个return语句
如果一个lambda体包含除return语句外的任何语句,则编译器会判定此lambda返回void
auto f3 = [](int a) {//此时会推断返回为void类型而报错
if (a < 10)
return a;
else
return -a; };
为避免此类问题,可以指定返回类型,来避免编译器的自动推断
auto f4 = [](int a)->int {
if (a < 10)
return a;
else
return -a; };
(新的编译器可能重新修订了这块,不指定返回类型也不会报错)。