Lambda表达式是C++11提供的一个新语法,使用起来非常方便。
在C++11之前,如果我们要使用sort函数进行排序,默认是排升序,如果我们想要排降序,就需要传递进一个库里面写好的仿函数。
#include
#include
int main()
{
int array[] = {4,1,8,5,3,7,0,9,2,6};
// 默认按照小于比较,排出来结果是升序
std::sort(array, array+sizeof(array)/sizeof(array[0]));
// 如果需要降序,需要改变元素的比较规则
std::sort(array, array + sizeof(array) / sizeof(array[0]), greater<int>());
return 0;
}
对于内置类型的排序,这种方法不算特别麻烦。但实际上我们使用的排序都不会是单一元素的排序,一般排序都是多种元素结合的排序,这就需要我们对自定义类型进行排序。比如结构体,我们要控制结构体内不同类型数据的比较规则,就需要自己写一个仿函数来控制排序。
比如我们要写一个学生信息的排序,按照身高高的学生优先,如果身高相同则年龄小的学生优先这样的规则进行排序。
#include
#include
#include
using namespace std;
struct Student
{
string _name; // 学生名字
int _age; // 学生年龄
int _height; // 学生身高
Student(const string &name, const int &age, const int &height)
: _name(name), _age(age), _height(height)
{
}
};
// 按照身高高的优先,如果身高相同则按年龄小的优先
struct CmpStudent
{
bool operator()(const Student& s1, const Student& s2)
{
if(s1._height == s2._height)
{
return s1._age < s2._age;
}
else
{
return s1._height > s2._height;
}
}
};
int main()
{
vector<Student> v = {{"张三", 18, 180}, {"李四", 15, 200}, {"王五", 13, 200}};
sort(v.begin(), v.end(), CmpStudent());
for(auto e : v)
{
cout << e._name << " - " << e._age << " - " << e._height << endl;
}
return 0;
}
上面实现排序的做法相对比较麻烦,我们可以采用Lambda表达式来简化它。
Lambda表达式其实是一种全新的定义函数的方法,它可以匿名定义一个函数。
例如上面的例子,我们可以利用Lambda表达式来简化:
#include
#include
#include
using namespace std;
struct Student
{
string _name; // 学生名字
int _age; // 学生年龄
int _height; // 学生身高
Student(const string &name, const int &age, const int &height)
: _name(name), _age(age), _height(height)
{
}
};
int main()
{
vector<Student> v = {{"张三", 18, 180}, {"李四", 15, 200}, {"王五", 13, 200}};
// Lambda表达式
sort(v.begin(), v.end(), [](const Student& s1, const Student& s2){
if(s1._height == s2._height)
{
return s1._age < s2._age;
}
else
{
return s1._height > s2._height;
}
});
for(auto e : v)
{
cout << e._name << " - " << e._age << " - " << e._height << endl;
}
return 0;
}
// Lambda表达式书写格式
[capture-list](parameters)mutable -> returntype{statement}
// 所以这是最简单的Lambda表达式,该Lambda表达式没有任何意义
[]{};
例如我们可以使用Lambda表达式写一个两数相加的Add函数:
#include
#include
#include
using namespace std;
int main()
{
int a = 10, b = 100;
auto Add = [](int x, int y)->int{
return x + y;
};
cout << Add(a, b) << endl;
return 0;
}
捕捉列表描述了上下文数据中哪些数据可以被Lambda表达式使用,它的使用非常灵活。
传值方式捕捉变量:
int main()
{
int a = 10, b = 20;
// 传值捕捉
auto Func1 = [a, b]{
return a + b;
};
cout << Func1() << endl;
return 0;
}
传引用方式捕捉变量:
int main()
{
int a = 10, b = 20;
// 传引用捕捉
auto Func2 = [&a, &b]{
int tmp = a;
a = b;
b = tmp;
};
Func2();
cout << a << " - " << b << endl;
return 0;
}
传值方式捕捉父作用域中的所有变量(包括this):
(父作用域指Lambda表达式语句所在的作用域)
int main()
{
int a = 10, b = 20, c = 1, d = 2, e = 3;
// 传值方式捕捉父作用域中的所有变量(包括this)
auto Func3 = [=]{
return a + b + c + d + e;
};
cout << Func3() << endl;
return 0;
}
传引用方式捕捉父作用域中的所有变量(包括this):
int main()
{
int a = 10, b = 20, c = 1, d = 2, e = 3;
// 传引用方式捕捉父作用域中的所有变量(包括this)
auto Func4 = [&]{
a = a + b + c + d + e;
};
Func3();
cout << a << endl;
return 0;
}
混合捕捉:
int main()
{
int a = 10, b = 20, ret = 0;
// 混合方式
auto Func5 = [a, b, &ret]{
ret = a + b;
};
Func5();
cout << ret << endl;
// ret传引用捕捉,其它全部传值捕捉
auto Func6 = [=, &ret]{
ret = a + b;
};
Func6();
cout << ret << endl;
return 0;
}
仿函数就是一个函数对象,是一个可以像函数一样使用的对象,它的类里重载了operator()运算符。
// 函数对象
class AddUtil
{
public:
AddUtil(int a = 0, int b = 0)
: _a(a), _b(b)
{
}
int operator()()
{
return _a + _b;
}
private:
int _a;
int _b;
};
int main()
{
AddUtil A(10, 20);
cout << A() << endl;
return 0;
}
Lambda表达式实际在底层实现的时候,编译器是完全按照函数对象的方式来处理的,如果我们定义了一个Lambda表达式,编译器会自动生成一个类,在该类中重载operator()。