(C++11/14/17学习笔记):lambda表达式的使用
程序员文章站
2022-05-03 23:34:59
目录用法介绍捕获列表 []lambda表达式延迟调用易出错细节分析lambda表达式中的mutable (易变的)lambda表达式的类型及存储lambda表达式再演示和优点总结用法介绍lambda表达式是一种可调用对象。它定义了一个函数,并且可以捕获一定范围内的变量。auto f = [](int a)->int { return a+1};cout << f(1) << endl; //输出 2特点:是....
目录
用法介绍
- lambda表达式是一种可调用对象。
- 它定义了一个函数,并且可以捕获一定范围内的变量。
auto f = [](int a)->int { return a+1 }; cout << f(1) << endl; //输出 2
- 特点:
- 是个匿名函数,也可以理解为“可调用的代码单元” ,或者理解成未命名的内联函数。
- 它有一个返回类型,一个参数列表,一个函数体。
- 与函数不同的是,lambda表达式可以在函数的内部定义,这是常规函数做不到的。
- 格式:
[捕获列表](参数列表)->返回类型(函数体);
- 注意结尾有分号。
- 因为很多时候lambda表达式返回值类型特别明显,所以允许lambda表达式返回值类型省略,编译器可以自动推导。
- 编译器不是总能推断出返回值类型,如果编译器不能推断出类型就会报错,这个时候就需要你显示的给出返回值类型。
auto f = [](int a = 10) { return a+1 }; cout << f(1) << endl; //输出 11
- 没有参数的时候,参数列表可以省略,甚至()也能省略,所以如下写法也是合法的:
auto f1 = [](){ return 1; }; auto f2= [] { return 2; }; cout << f1() << endl; //输出1 cout << f2() << endl; //输出2
- 捕获列表和函数体不能省略,必须时刻包含。
- lambda调用方法和普通函数相同,都是使用()这种函数调用运算符。
- lambda表达式可以不返回任何类型,不返回的类型就是 void。
auto f = [] {};
- lambda表达式函数体末尾分号不能省略。
捕获列表 []
[捕获列表]:通过捕获列表来捕获一定范围内的变量,范围是什么意思?
a[] 不捕获任何变量
int i = 9; auto f = [] { return i; };
- 编译报错(无法捕获外部变量),不认识i 在哪里定义。
- 注意:a[] 不捕获任何变量,但不包括静态局部变量。lambda表达式可以直接使用局部静态变量(局部静态变量不需要捕获的)
static int i = 9; auto f = [] { return i; };
[&] 捕获外部作用域中的所有变量,并作为引用在函数体内使用。
int i = 9 ; auto f = [&] { i = 5; return i; }; cout << f() << endl; //输出 5 cout << i << endl; //输出 5
- 因为 & 的存在,那么就允许给 i 赋值,从而就改变了 i 的值。
- 注意 i 的范围,其他地方调用f(),保证其内部的变量有效。
[=]:捕获外部作用域中所有变量,并作为副本(按值)在函数中使用,也就是可以用它的值,但不允许给它赋值。
int i = 9; auto f = [=] { // i = 5; 非法,不可以给它赋值,因为是以值的方式捕获。 return i; }; cout << f() << endl; 输出9
[this] :一般用于类中,捕获当前类中的this指针,让lambda表达式有和当前类成员函数同样的访问权限。
- 如果 [] 中已经使用了 & 或者 = ,那么默认就已经使用了 this ,捕获this 的目的是为了在lambda表达式中使用当前类的成员函数和成员变量。
class Te { public: int m__ = 5; void func(int x, int y){ auto my_lambda = [this]{ //无论是this,还是 & 或者 = 都可以达到访问类成员的目的 return m__; //因为有了this,这个访问是合法的 }; } }; int main(){ Te t; t.func(3, 4); //输出 5 return 0; }
[变量名] :如果是多个变量名。彼此之间用 逗号分隔。[变量名] 表示按值捕获变量名代表的变量,同时不捕获其他变量。
class Te { public: int m__ = 5; void func(int x, int y){ auto my_lambda = [this,x ,y ]{ m__ = x + y; //捕获x, y,可以使用,不能修改x,y的值 return m__; }; } };
[&变量名] :如果是多个变量名。彼此之间用 逗号分隔。[变量名] 表示按引用捕获变量名代表的变量,同时不捕获其他变量。
class Te { public: int m__ = 5; void func(int x, int y){ auto my_lambda = [this,x ,y ]{ x = 5; y = 5; return m__; }; } };
[= , &变量名] :按值捕获所有外部变量,但按引用捕获&中所指的变量,这里这个=必须写在开头位置,开头这个位置表示默认捕获方式。
- 也就是说,这个捕获列表,第一个位置表示的是默认捕获方式(隐式捕获方式),后续其他的都是显式捕获方式。
class Te { public: int m__ = 5; void func(int x, int y){ auto my_lambda = [this, &x ]{ x = 5; //显示指定引用方式捕获,可以修改 y = 5; //默认按值捕获,不能修改 return m__; }; } };
[&, 变量名]:按引用来捕获所有外部变量,但按值来捕获变量名所代表的变量,这里这个&必须写在开头位置,开头表示的是默认捕获方式。
class Te { public: int m__ = 5; void func(int x, int y){ auto my_lambda = [&, x ]{ x = 5; //显示指定按值捕获,不能修改 y = 5; //默认指定引用方式捕获,可以修改 return m__; }; } };
lambda表达式延迟调用易出错细节分析
intx=5; auto f = [=] { return x; }; x=10; cout << f() << endl;
- 上面输出为 5 。
- 当遇到auto这一 行,也就是在捕获的这个时刻,x的值就已经被复制到了这个f 中了。
- 凡是按值捕获的外部变量,在lambda表达式定义的这个时刻,所有这些外部变量值就被复制了一份存储在lambda表达式变量中。
- 如果想要使用最新的值,则使用 & 进行捕获。
lambda表达式中的mutable (易变的)
intx=5; auto f = [=]()mutable{ x=6; //可以修改 return x; }
- 注意mutable前面的圆括号不能省略。
lambda表达式的类型及存储
- c++11中lambda表达式的类型被称呼为“闭包类型(Closure Type)”。
- 闭包:函数内的函数(可调用对象)。本质上就是lambda表达式创建的运行时期的对象。
- lambda表达式是一种比较特殊的,匿名的,类类型【闭包类】的对象(也就是定义了一个类类型,又生成一个匿名的类类型的对象(闭包)。
- 我们可以认为它是一个带有operator()的类类型对象,也就是仿函数(函数对象)。
- 所以,我们也可以用 std::function 和 std::bind 来保存和调用lambda表达式。每个lambda都会触发编译器给咱们生成独一无二的类类型对象。
- lambda表达式这种语法,是我们可以就地定义匿名函数(就地封装短小的功能闭包)。
auto f = []{};
- f 是个未命名的类类型对象。
- 捕获到的变量类似于作为这个匿名的类类型对象的成员变量。
std::function<int(int)> fc1 = [](int v){ return v; }; std::cout << fc1(6) <<std::endl; //输出6 std::function<int(int)> fc2 = std::bind([](int v){ //bind第一个参数是函数指针(函数对象),第二个参数开始 就是真正的函数参数。 return v; }, 16 ); std::cout << fc2(1) <<std::endl; //输出16
- 不捕获任何变量的lambda表达式,也就是捕获列表为空,可以转换成一个普通的函数指针。
using functype = int(*)int);//定义一个函数指针类型; functype fp = [](int tv){ return tv; }; cout << fp(17)<< endl; //输出17
语法糖概念
- 语法糖:一种便捷写法的意思。
int a[5]; a[0]=1; //便捷写法(语法糖) *(a+1) = 3://a[1]=3
- 语法糖这个词,让我们写的代码更简单,看起来也更容易理解,有效的减少些代码出错的机率。
- 语法糖是指基于语言现有特性,构建出一个东西,程序员用起来会很方便。但它没有增加语言的原有功能。
- 所以,这个lambda表达式,大家也可以看成是定义仿函数闭包(函数中的函数)。
lambda表达式再演示和优点总结
- for_each:是个函数模板
void myfunc(int i){ cout << i << endl; } ... //在main中调用 vector<int> myvector = { 10, 20, 30, 40, 50 }; for_each(myvector.begin(), myvector.end(), myfunc); //输出 10 20 30 40 50
- 使用lambda表达式
vector<int>myvector={10,20,30,40,50}; int sum = 0; for_each( myvector.begin(), myvector.end(), [&sum](int val){ sum += val; cout << val << endl; } ); cout << sum << endl; //输出150
find_if简介:函数模板find_if
- 用来查找一个东西,查什么东西呢?取决于它的第三个参数,它的第三个参数也是个函数对象(lambda表达式)。
vector<int> myvector={10, 20, 30, 40, 50}; auto result = find_if(myvector.begin(), myvector.end(), [](int val){ cout << val << endl; return false; //只要我返回false,那么find_if就不停的遍历myvecotr。一直到返回true或者遍历完为止。 })
- 如果find if第三个参数这个可调用对象(lambda)返回true,find_if就停止遍历。
vector<int> myvector={10, 20, 30, 40, 50}; auto result = find_if(myvector.begin(), myvector.end(), [](int val){ cout << val << endl; if(val > 15) return true; //返回true,停止遍历 return false; })
本文地址:https://blog.csdn.net/baidu_41388533/article/details/110844621
上一篇: SpringCloud微服务(Fegin负载均衡遇到的问题和解决方案)
下一篇: 典型的脑残