文章目录
- 1. C++98对自定义类型的排序
- 2. lambda表达式语法
- 2.1 捕捉列表
- 3. lambda底层原理
1. C++98对自定义类型的排序
在C++98中,想要对自定义类型就行排序,我们得自己写仿函数来表明我们相对哪一项进行排序
struct Student
{
Student(string name, long id, double score)
:_name(name)
,_id(id)
,_score(score)
{}
string _name;
long _id;
double _score;
};
//按名字排序 -- 降序
struct CmpName
{
bool operator()(const Student& stu1, const Student& stu2)
{
return stu1._name < stu2._name;
}
};
//按学号排序 -- 降序
struct CmpId
{
bool operator()(const Student& stu1, const Student& stu2)
{
return stu1._id < stu2._id;
}
};
//按分数排序 -- 降序
struct CmpScore
{
bool operator()(const Student& stu1, const Student& stu2)
{
return stu1._score < stu2._score;
}
};
int main()
{
vector<Student> v = { {"张三",101,99.3},{"李四",104,85.2},{"王五",102,99.9} };
sort(v.begin(), v.end(),CmpName());
sort(v.begin(), v.end(),CmpId());
sort(v.begin(), v.end(),CmpScore());
return 0;
}
如果代码风格较好,然后加上了注释,这其他人一看就懂是什么意思。但如果命名不规范,就是个很头疼的问题。
例如:
int main()
{
vector<Student> v = { {"张三",101,99.3},{"李四",104,85.2},{"王五",102,99.9} };
sort(v.begin(), v.end(),Cmp1());
sort(v.begin(), v.end(),Cmp2());
sort(v.begin(), v.end(),Cmp3());
return 0;
}
这里的仿函数,我们看到就不知道是对哪一项进行排序,就得往前翻,如果前面的命名也不规范,那就十分痛苦。
而且一旦我们的对象的参数多了,那我们就得写出对应的仿函数,这不是很方便,于是在C++11中出现了lambda
表达式
2. lambda表达式语法
lambda
表达式格式:[capture-list] (parameters) mutable -> return-type { statement }
示例:
[] (int x,int y)->int { return x+y;}
-
lambda
表达式各部分说明[]
:捕捉列表,该列表总是出现在lambda
函数的开始位置,编译器根据[]
来 判断接下来的代码是否为lambda
函数,捕捉列表能够捕捉上下文中的变量供lambda
函数使用。()
:参数列表。与普通函数的参数列表一致,如果不需要参数传递,则可以 连同()一起省略。mutable
:默认情况下,lambda
函数总是一个const
函数,mutable
可以取消其常量性。使用该修饰符时,参数列表不可省略(即使参数为空)。->returntype
:返回值类型。用追踪返回类型形式声明函数的返回值类型,没有返回值时此部分可省略。返回值类型明确情况下,也可省略,由编译器对返回类型进行推导。{statement}
:函数体。在该函数体内,除了可以使用其参数外,还可以使用所有捕获到的变量。
int main()
{
vector<Student> v = { {"张三",101,99.3},{"李四",104,85.2},{"王五",102,99.9} };
sort(v.begin(), v.end(), [](const Student& stu1, const Student& stu2)->bool {return stu1._name < stu2._name; });
sort(v.begin(), v.end(), [](const Student& stu1, const Student& stu2)->bool {return stu1._id < stu2._id; });
sort(v.begin(), v.end(), [](const Student& stu1, const Student& stu2)->bool {return stu1._score < stu2._score; });
return 0;
}
2.1 捕捉列表
-
[var]:表示值传递方式捕捉变量var
int a = 1; int b = 2; double rate = 2.5; auto f1 = [rate](int x, int y) {return x + y; }; cout<<f1(a,b)<<endl; //输出 7.5
-
[&var]:表示引用传递捕捉变量var
适用于对象较大或者需要修改捕捉列表里面的值
int a = 1; int b = 2; auto swap1 = [a, b]() mutable { //mutable让捕捉的a b可以修改 //但这里面的a b 属于是外面a b的拷贝 int tmp = a; a = b; b = tmp; }; swap1(); auto swap2 = [&a, &b] { //捕捉引用,可以直接修改外面a b的值了 int tmp = a; a = b; b = tmp; }; swap2();
-
[=]:表示值传递方式捕获所有父作用域中的变量(包括this)
捕捉所有的外部变量
int a = 1; int b = 2; int c = 3; auto f2 = [=]() { cout << a << " " << b << " " << c << " " << endl; }; f2();
-
[&]:表示引用传递捕捉所有父作用域中的变量(包括this)
捕捉所有外部变量的引用
int a = 1; int b = 2; int c = 3; auto f3 = [&]() { cout << ++a << " " << ++b << " " << ++c << " " << endl; }; f3(); cout << a << " " << b << " " << c << " " << endl; //也可以混合捕捉,这里的a就是不可修改的了,普通捕捉 auto f4 = [&, a] { cout << a << " " << ++b << " " << ++c << " " << endl; }; cout << a << " " << b << " " << c << " " << endl;
-
[this]:表示值传递方式捕捉当前的this指针
3. lambda底层原理
int main()
{
auto f1 = [](int x, int y) {return x + y; };
auto f2 = [](int x, int y) {return x + y; };
//f1 = f2; //error
cout << typeid(f1).name() << endl;
cout << typeid(f2).name() << endl;
return 0;
}
这段代码运行之后发现,f1
和f2
的类型是类
这里lambda
的底层就是一个仿函数,就和范围的for
的底层就是迭代器一样,上层将其封装了,调用的就是类的operator()