概述
前言:
将以前自己做的lambda表达式的笔记传到博客上来,一来供自己查阅,二来给有需要的人提供思路。
文章目录
- 0x01)lambda表达式
- 1、lambda表达式形式如下:[capture] (parameters) mutable ->return-type{statement}
- 2、向lambda传递参数
- 3、使用捕获列表
- 4、调用find_if
- 5、for_each算法
- 6、完整的biggies
- 0x02)lambda捕获和返回
- 1、值捕获
- 2、引用捕获
- 3、隐式捕获
- 4、可变lambda
- 5、指定lambda返回类型
0x01)lambda表达式
我们可以向一个算法传递任何类型的可调用对象。
对于一个对象或一个表达式,如果可以对其使用调用运算符,则称它为可调用的。比如e是一个可调用的表达式,则我们可以编写代码e(args),其中args是一个都好分的一个或多个参数的列表。
**可调用的对象:**函数、函数指针、重载了调用运算符的类以及lambda表达式。
一个lambda表达式表示一个可调用的代码单元,我们可以将其理解为一个未命名的内联函数。
与任何函数类似,一个lambda表达式具有一个返回类型,一个参数列表和一个函数体。但与函数不同,lambda可能定义在函数内部。
1、lambda表达式形式如下:[capture] (parameters) mutable ->return-type{statement}
1.[capture]:捕捉列表。捕捉列表总是出现在Lambda函数的开始处。实际上,[]是Lambda引出符。编译器根据该引出符判断接下来的代码是否是Lambda函数。捕捉列表能够捕捉上下文中的变量以供Lambda函数使用;
2.(parameters):参数列表。与普通函数的参数列表一致。如果不需要参数传递,则可以连同括号“()”一起省略;
3.mutable:mutable修饰符。默认情况下,Lambda函数总是一个const函数,mutable可以取消其常量性。在使用该修饰符时,参数列表不可省略(即使参数为空);
4.->return-type:返回类型。用追踪返回类型形式声明函数的返回类型。我们可以在不需要返回值的时候也可以连同符号”->”一起省略。此外,在返回类型明确的情况下,也可以省略该部分,让编译器对返回类型进行推导(auto);
5.{statement}:函数体。内容与普通函数一样,不过除了可以使用参数之外,还可以使用所有捕获的变量。
与普通函数最大的区别是,除了可以使用参数以外,Lambda函数还可以通过捕获列表访问一些上下文中的数据。具体地,捕捉列表描述了上下文中哪些数据可以被Lambda使用,以及使用方式(以值传递的方式或引用传递的方式)。语法上,在“[]”包括起来的是捕捉列表,捕捉列表由多个捕捉项组成,并以逗号分隔。捕捉列表有以下几种形式:
1.[var]表示值传递方式捕捉变量var;
2.[=]表示值传递方式捕捉所有父作用域的变量(包括this);
3.[&var]表示引用传递捕捉变量var;
4.[&]表示引用传递方式捕捉所有父作用域的变量(包括this); 5.[this]表示值传递方式捕捉当前的this指针;
6.[]表示一个空捕获列表,它不使用任何在lambda{}中的局部变量。 7.[=,&identifier_list]identifier中的变量采用引用方式捕获,但是其中不能包含this指针。
注意:这里的父作用域就是包含lambda表达式的整个作用域,即lambda表达式在这个{}作用域中,不是lambda表示式里的函数体{}。
举例如下:
#include <iostream>
using namespace std;
int main()
{
int j = 10;
auto by_val_lambda = [=]()mutable{return j + 1; };
auto by_ref_lambda = [&]{return j + 1; };
cout << "by_val_lambda:" <<by_val_lambda() << endl;
cout << "by_ref_lambda:" << by_ref_lambda() << endl;
++j;
cout << "by_val_lambda:" << by_val_lambda() << endl;
cout << "by_ref_lambda:" << by_ref_lambda() << endl;
system("pause");
return 0;
}
输入结果:11 11 11 12
对于by_val_lambda由于捕获列表是进行的值拷贝,所以被捕获变量的值在lambda创建时拷贝,而不是调用时拷贝。这样可解释by_val_lambda中的j的值创建时被拷贝为10,一旦拷贝完成,随后父作用域对j进行修改也不会影响到lambda内对应的j的值。
对于by_ref_lambda由于调用by_ref_lambda()的引用j绑定的是全局作用域的j,所以全局作用的j变化,调用它时j也会发生变化,它的变化也会影响到全局作用域中的j。
2、向lambda传递参数
与一个普通函数调用类型,调用一个lambda时需要用给定的实参来初始化lambda的形参。
/*按长度排序,长度相同的单词维持字典序*/
stable_sort(words.begin(),words.end(),[](const string& a,const string& b){return a.size()<b.size();});
空捕获列表表明此lambda不使用lambda{}中的任何局部变量
当stable_sort需要比较两个元素时,它就会调用给定的这个lambda表达式。
3、使用捕获列表
虽然一个lambda可以出现在一个函数中,使用其局部变量,但是它只能使用那些明确指明的变量。一个lambda通过将局部变量包含在其捕获列表中来指出将会使用的这些变量。捕获列表指引lambda在其内部包含访问局部变量所需的信息。
[sz](const string& a){return a.size()>=sz;};
注:只有捕获了sz,函数体中才能使用sz这个局部变量。
4、调用find_if
/*获取第一个满足长度大于sz元素的迭代器。若找不到长度大于sz的元素则返回words.end()的拷贝*/
/*前提是:words按长度排序,长度相同的单词维持字典序*/
auto wc=find_if(words.begin(),words.end(),[sz](const string& a){return a.size()>=sz;});
5、for_each算法
/*打印长度大于等于给定值的单词,每个单词后面接一个空格*/
for_each(wc,words.end(),[](const string& s){cout<<s<<" ";});
我们只在lambda所在函数中定义的==(非static)变量==使用捕获列表。一个lambda也可以使用定义在当前函数之外的名字。
6、完整的biggies
void biggies(vector<string> &words,vector<string>::size_type sz)
{
elimDups(words);//将words按字典排序,删除重复单词
/*按长度排序,长度相同的单词维持字典序*/
stable_wort(words.begin(),words.end(),[](const string& a,const string& b){return a.size()<b.size();});
/*获取一个迭代器,指向第一个满足size()>sz的元素*/
auto wc=find_if(words.begin(),words.end(),[sz](const string& a){return a.size()>=sz;});
/*计算满足size>=sz的元素的数目*/
auto count=words.end()-wc;
/*打印长度大于等于给定值的单词,每个单词后面接一个空格*/
for_each(wc,words.end(),[](const string &s){cout<<s<<" ";});
cout<<endl;
}
0x02)lambda捕获和返回
当定义一个lambda时,编译器生成一个与lambda对应的新的(未命名的)类类型。
即向一个函数传递一个lambda时,同时定义了一个新类型和该类型的一个对象:传递的参数就是此编译器生成的类类型的未命名对象。类似的,当使用auto定义一个用lambda初始化的变量时,也就是定义了一个从lambda生成的类型的对象。
1、值捕获
lambda表达式采用值捕获的前提是捕获的变量可以拷贝。与参数不同的是,被捕获的变量的值是在lambda创建时拷贝,而不是调用时拷贝。
由于被捕获变量的值是在lambda创建时拷贝,因此随后对其修改不会影响到lambda内对应的值。
void test()
{
size_t v1=42;//局部变量
auto f=[v1]{return v1;};/*将v1拷贝到名为f的可调用对象*/
v1=0;
auto j=f();//j=42,f保存了我们创建它时v1的拷贝
}
2、引用捕获
void test()
{
size_t v1=42;//局部变量
//对象f2包含v1的引用
auto f2=[&v1]{return v1;};
v1=0;
auto j=f2();//j=0,f保存了v1的引用,而非拷贝
}
一个以引用方式捕获的变量与其他任何类型的引用的行为类似。当我们在lambda函数体内使用此变量时,实际上使用的是引用所绑定的对象。本例中,当lambda返回v1时,它返回的是v1所指向的对象的值。
当以引用方式捕获一个变量时,必须保证在lambda执行时变量是存在的。
3、隐式捕获
为了指示编译器推断捕获列表,应在捕获列表中写一个&或=
4、可变lambda
由于默认情况下lambda是一个const函数,所以对于一个以值被拷贝的变量,需要在参数列表前面添加关键字matable来修改被捕获的变量的值。
5、指定lambda返回类型
默认情况下,如果一个lambda包含return之外的任何语句,则编译器假定lambda返回void,因此返回void的lambda不能有返回值。
当lambda体是单一的return语句时,返回一个条件表达式的结果,我们无需指定其返回类型,编译器可根据条件运算符的类型来推导。
当我们需要为一个lambda定义返回类型时,必须使用尾置返回类型。
最后
以上就是健忘母鸡为你收集整理的C++:lambda表达式的全部内容,希望文章能够帮你解决C++:lambda表达式所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复