以下是阿鲤对lambda表达式的学习总结,希望对大家有所帮助
一:lambda表达式的存在意义
二:lambda的语法
三:lambda的原理
一:lambda表达式的存在意义
在c++98中我们想要给一个自定义类型的数组进行排序,我们需要设计自己的排序规则,再将排序规则传入sort函数中,如下
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
class student
{
string m_name;
string m_sex;
int m_age;
public:
student() = default;
student(string name, string sex, int age):
m_name(name),
m_sex(sex),
m_age(age)
{}
friend class compare;
};
class compare
{
public:
bool operator()(student s1, student s2)
{
if (s1.m_age > s2.m_age)
{
return true;
}
else if(s1.m_age == s2.m_age)
{
if (s1.m_name > s2.m_name)
{
return true;
}
}
else
{
return false;
}
return false;
}
};
int main()
{
vector<student> v;
student s1("peter", "man", 18);
student s2("peter", "female", 19);
student s3("peter", "man", 20);
v.push_back(s1);
v.push_back(s2);
v.push_back(s3);
sort(v.begin(), v.end(), compare());
return 0;
}
这样下来,我们每次为了比较就得写一个仿函数,这样就非常的麻烦,那么lambad表达式的出现就是来解决这个问题的。
二:lambda的语法
首先给出上面代码的lambda表达式
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
class student
{
public:
string m_name;
string m_sex;
int m_age;
student() = default;
student(string name, string sex, int age):
m_name(name),
m_sex(sex),
m_age(age)
{}
};
int main()
{
vector<student> v;
student s1("peter", "man", 18);
student s2("peter", "female", 19);
student s3("peter", "man", 20);
v.push_back(s1);
v.push_back(s2);
v.push_back(s3);
sort(v.begin(), v.end(), [](student &s1, student &s2)
{
if (s1.m_age > s2.m_age)
{
return true;
}
else if (s1.m_age == s2.m_age)
{
if (s1.m_name > s2.m_name)
{
return true;
}
}
else
{
return false;
}
return false;
}
);
return 0;
}
这样写下来是不是就感觉轻松了很多呢。
语法介绍:[capture-list](parameters)mutable->return-type{statement}
1:lambda表达式各部分说明
[capture-list]:捕捉列表,该列表总是在lambda函数最开始的位置,编译器根据[]来判断接下来的代码是否为lambda函数,捕捉列表能够捕捉上下文中的变量供lambda函数使用
(parmameters):参数列表。与普通函数的参数列表一致,如果不需要传递参数,则可以连同()一起省略
mutable:默认情况下,lambda函数总是一个const函数,加上mutable后可以取消其常量性。使用该修饰符时,参数列表不可以为空。
->return-type:返回值类型。用追踪返回类型的型式声明函数的返回值类型,没有返回值时此部分可省略。返回值类型明确时也可以省略。
{statement}:函数体。
注意:在lambda函数定义中,参数列表和返回值类型都是可选部分,而捕捉列表和函数体可以为空。比如:[]{}
2:捕捉列表说明:
捕捉列表描述了那些数据可以被捕捉,以及使用方式是值还是引用
[var]:表示以值传递的方式捕捉var
[=]:表示以值传递的方式捕获所有父作用域的变量(包括this)
[&var]:表示以引用捕捉var
[&]:表示以引用捕捉父作用域中的所有变量(包括this)
[this]:表示以值传递的方式捕捉当前的this指针
注意:
1:父作用域指包括lambda的语句块
2:语法上捕捉列表可由多个捕捉顶组成,并以逗号分隔
3:在块作用域以外的lambda函数捕捉列表必须为空
4:捕捉列表不允许重复传递
5:捕捉列表只能捕捉父作用域的局部变量
6:lambda之间不可以相互赋值
eg:
int m_d = 9;
int main()
{
int a = 5;
int b = 6;
[] {};// 空的lambda表达式
auto f1 = [a](int c) {c = a; };//以传值的方式:a不能改变值(比如a = 10的操作是违法的)
auto f2 = [=](int c) {c = a + b + m_d; };//已传值的方式引入所有的父作用域变量
auto f3 = [&]{a = 1, b = 2; };//传引用,可改
auto f4 = [=, &a] {a = b + m_d; };//传值,只有a传引用
auto f5 = [&, a] {b = a + m_d; };//传引用,只有a传值
//auto f6 = [&, &a] {}//非法操作,不可重复同类型
return 0;
}
三:lambda的原理
我们在前面讲到lambda表达式之间不可以相互赋值,那么这是为什么呢?下面我们将揭晓
#include<iostream>
using namespace std;
void(*pf)();
int m_d = 9;
int main()
{
int a = 5;
int b = 6;
auto f1 = [] {cout << "hello eord" << endl; };
auto f2 = [=](int c) {c = a + b + m_d; };
pf = f1;//我们发现可以将lambda表达式赋值给同类型的函数指针
//f2 = f1; 错误操作
auto f3(f1);//但是却可以拷贝构造
//我们打印一下f1,f2的类型
cout << "f1 : " << typeid(f1).name() << endl;
cout << "f2 : " << typeid(f2).name() << endl;
cout << "f3 : " << typeid(f3).name() << endl;
cout << "pf : " << typeid(pf).name() << endl;
return 0;
}
运行结果:
我们发现f1,f2就是一个类,而f3则是拷贝了f1
然后我们看一下f1,f2的汇编代码
我们就会1发现,f1,f2的汇编代码和函数对象(仿函数)格式是一样的,这样我们就知道了lambda的底层是通过仿函数来实现的。