前言:
一般来说函数是承担着需求实现的重要内聚的组件,而函数内部的回调函数又达到解耦的作用,在对于后期的维护修改和他人的阅读都起到了积极的作用。
1、lambda表达式的诞生
在有时函数的本身的标准化让老油条的前辈们感到一丝丝的麻烦,例如算法库(algorithm)中的sort()函数,
为了同时实现排序的升序和降序(不传入comp,默认为升序),我们会传入比较函数对象
例如下面的 myfunction ()与 仿函数myclass
代码语言:javascript复制#include <iostream> // std::cout
#include <algorithm> // std::sort
#include <vector> // std::vector
bool myfunction (int i,int j) { return (i<j); }
struct myclass {
bool operator() (int i,int j) { return (i<j);}
} myobject;
int main () {
int myints[] = {32,71,12,45,26,80,53,33};
std::vector<int> myvector (myints, myints 8); // 32 71 12 45 26 80 53 33
// using default comparison (operator <):
std::sort (myvector.begin(), myvector.begin() 4); //(12 32 45 71)26 80 53 33
// using function as comp
std::sort (myvector.begin() 4, myvector.end(), myfunction); // 12 32 45 71(26 33 53 80)
// using object as comp
std::sort (myvector.begin(), myvector.end(), myobject); //(12 26 32 33 45 53 71 80)
// print out content:
std::cout << "myvector contains:";
for (std::vector<int>::iterator it=myvector.begin(); it!=myvector.end(); it)
std::cout << ' ' << *it;
std::cout << 'n';
return 0;
}
这就让人让人无语了,就为了一个大于和小于,还额外写函数。。。。。
2、lambda表达式语法
lambda表达式书写格式:
[capture-list] (parameters) mutable -> return-type { statement}
2.1、lambda表达式各部分说明
- [capture-list] : 捕捉列表:该列表总是出现在lambda函数的开始位置,编译器根据[]来判断接下来的代码是否为lambda函数,捕捉列表能够捕捉上下文中的变量供lambda函数使用。
- (parameters):参数列表:与普通函数的参数列表一致,如果不需要参数传递,则可以连同()一起省略
- mutable:默认情况下:lambda函数总是一个const函数,mutable可以取消其常量性。使用该修饰符时,参数列表不可省略(即使参数为空)。
- ->returntype:返回值类型:用追踪返回类型形式声明函数的返回值类型,没有返回 值时此部分可省略。返回值类型明确情况下,也可省略,由编译器对返回类型进行推 导。
- {statement}:函数体:在该函数体内,除了可以使用其参数外,还可以使用所有捕获 到的变量。
注意: 在lambda函数定义中,参数列表和返回值类型都是可选部分,而捕捉列表和函数体可以为 空。因此C 11中最简单的lambda函数为:[]{}; 该lambda函数不能做任何事情。
例子:
代码语言:javascript复制int main()
{
// 最简单的lambda表达式, 该lambda表达式没有任何意义
[]{};
// 省略参数列表和返回值类型,返回值类型由编译器推导为int
int a = 3, b = 4;
[=]{return a 3; };
// 省略了返回值类型,无返回值类型
auto fun1 = [&](int c){b = a c; };
fun1(10)
cout<<a<<" "<<b<<endl;
// 各部分都很完善的lambda函数
auto fun2 = [=, &b](int c)->int{return b = a c; };
cout<<fun2(10)<<endl;
// 复制捕捉x
int x = 10;
auto add_x = [x](int a) mutable { x *= 2; return a x; };
cout << add_x(10) << endl;
return 0;
}
通过上述例子可以看出,lambda表达式实际上可以理解为无名函数,该函数无法直接调 用,如果想要直接调用,可借助auto将其赋值给一个变量。
2.2、捕获列表说明
捕捉列表描述了上下文中那些数据可以被lambda使用,以及使用的方式传值还是传引用。
- [var]:表示值传递方式捕捉变量var
- [=]:表示值传递方式捕获所有父作用域中的变量(包括this)
- [&var]:表示引用传递捕捉变量var
- [&]:表示引用传递捕捉所有父作用域中的变量(包括this)
- [this]:表示值传递方式捕捉当前的this指针
注意: a. 父作用域指包含lambda函数的语句块 b. 语法上捕捉列表可由多个捕捉项组成,并以逗号分割。
比如:[=, &a, &b]:以引用传递的方式捕捉变量a和b,值传递方式捕捉其他所有变量 [&,a, this]:值传递方式捕捉变量a和this,引用方式捕捉其他变量
c. 捕捉列表不允许变量重复传递,否则就会导致编译错误。 比如:[=, a]:=已经以值传递方式捕捉了所有变量,捕捉a重复
d. 在块作用域以外的lambda函数捕捉列表必须为空。 e. 在块作用域中的lambda函数仅能捕捉父作用域中局部变量,捕捉任何非此作用域或者 非局部变量都会导致编译报错