文章目录
- lambda表达式
lambda表达式
lambda表达式可以看作一个匿名函数
-
语法
[capture-list] (parameters) mutable -> return-type { statement }
auto func1 = [](int a, int b) mutable -> int {return a + b; };
-
*capture-list:捕捉列表。编译器根据[]来 判断接下来的代码是否为lambda函数,捕捉列表能够捕捉上下文中的变量供lambda 函数使用。
-
捕捉列表描述了上下文中那些数据可以被lambda使用,以及使用的方式传值还是传引用。
-
[var]:传值捕捉。
传值捕捉,就相当于将实参传入形参一样。只是形参名和实参名形态
表示值传递方式捕捉变量var [=]:表示值传递方式捕获所有父作用域中的变量(包括this) -
[=]:对使用对象进行传值捕捉
表示值传递方式捕获所有父作用域中的变量(包括this) -
[&var]:传引用捕捉。
表示引用传递捕捉变量var -
[&]:对所有变量进行引用捕捉
表示引用传递捕捉所有父作用域中的变量(包括this) -
[this]:
表示值传递方式捕捉当前的this指针 -
混合捕捉:即上述的捕捉方式可以混合使用
int main() { int a = 10 , b = 20 , c = 30 , d = 50; auto test1 = [&a,b] { a++; //b不能修改,因为是 传值捕捉 的是有const属性的。 } auto test2 = [=,&a,&c] { a++; c++; //b,d不能修改,因为其被 传值捕捉,具有const属性 } auto test3 = [&,a,b] { c++; d++; //a,b不能修改,因为a,b是 传值捕捉 , 具有const属性 } }
-
-
-
parameters:参数:无参数时,(参数)可以省略。但是当需要显示写return-type时,即使没有参数,也不能将括号省略掉
auto func5 = []()->int { cout << "hello world" << endl; return 1; };
-
可变关键字:mutable。mutable相当于去掉了 捕获列表值捕捉的数据的const属性,使得其可以被修改。 在不需要的时候可以省略不写
使用mutable的时候,参数即使为空,也不能省略括号
int main() { int a = 10 , b = 20; // 下面的写法是错误的,因为 捕获列表 // auto swap = [a,b] // { // int tmp = a; // a = b; // b = tmp; // } //此处就能编译通过了,mutable取消了值捕捉的a,b的常性。但是此处达不到swap的要求,因为是值捕捉的数据 auto swap = [a,b]()mutable { int tmp = a; a = b; b = tmp; } //如此就达到swap的要求了,用引用捕捉来达到效果,mutable只是对值捕捉有用,即取消 值捕捉到的变量的常性 auto swap1 = [&a,&b]() { int tmp = a; a = b; b = tmp; } }
因此可以看出,mutable的用处不大,因为其虽然可以取消传值捕捉的变量的const属性,使其被修改,但是仍然没有对外部的变量进行修改。
-
return-type:返回值类型:没有返回值时->return-type可以省略;返回值明确时->return-type也可以省略,返回值类型由编译器自动推导
auto func3 = [](int a, int b){return a + b; };
-
statement:函数体
函数体中只能用lambda局部域和捕捉对象,以及全局对象int main() { int a = 10 , b = 20; auto swap1 = [](int& x , int& y) { int tp = x; x = y; y = x; } auto swap2 = [a,b] { } }
-
c++11中最简单的lambda表达式
auto func4 = [] { cout << "hello world" << endl; return 1; };
-
-
理解lambda表达式
-
lambda表达式的类型只能用auto去推导/function去包装
-
lambda表达式的底层
在底层上,lambda表达式和仿函数的实现是相同的,可以理解为在底层上lambda表达式就是生成一个函数对象
lambda表达式的捕捉列表的捕捉对象是以成员变量存在lambda类对象中。
捕捉的本质是lambda表达式的构造函数的初始化参数
看底层汇编实现
-
仿函数的创建和lambda表达式的创建
可以看出两个的行为是一样的。lambda表达式将字符串s当作实参传入自己的构造函数。仿函数print1将字符串s作为实参传入自己的构造函数
而且我们也可以看到,在底层剩下上lambda表达式的类型其实是可以被编译器确定的,此处为<lambda_1>,这里的_1是优化后的结果,实际上类型是lambda+UUID。
UUID是 通用唯一识别码。 是通过特殊算法使得真正唯一的任何地方产生的任意一个UUID都不会有相同的值。 -
仿函数的调用和lambda表达式对象的调用
显而易见,无论是仿函数还是lambda表达式,在调用时实际上都是调用其内部重写的operator()
-
-