C++ Lambda 表达式
什么是 C++ 中的 Lambda 表达式?
Lambda表达式(也叫lambda函数,匿名函数)是在调用或作为函数参数传递的位置处定义匿名函数对象的便捷方法。
语法定义
[捕获列表][参数列表][可变规则][返回值类型][函数体]
[ capture ]( params ) -> ret {body;};
其中capture是捕获列表,params是参数列表,ret是返回值类型,body是函数体。
捕获列表[]:捕获一定范围内的变量
参数列表(): 和普通函数的参数列表一样,如果没有参数参数列表可以省略不写
它的作用是什么?
提供一种简洁的方式来定义小型,局部的函数,特别是在使用算法和函数式编程风格时非常方便。
工作原理:
编译器会把一个lambda表达式生成一个匿名类的匿名对象,并在类中重载函数调用运算符,实现了一个operator()方法。
class print_class
{
public:
void operator()(void) const
{
cout << "Hello World!" << endl;
}
};
//用构造的类创建对象,print此时就是一个函数对象
auto print = print_class();
Lambda 表达式可以捕获哪些类型的变量?有哪些捕获方式?
- [ ] 不捕获任何变量
- [&] 捕获外部作用域中的所有变量,并且按照引用捕获
- [=]捕获外部作用域的所有变量,按照值捕获,拷贝过来的副本在函数体内是只读的
- [= ,&a] 按值捕获外部作用域中的所有变量,并且按照引用捕获外部变量 a
- [bar] 按值捕获bar变量,不捕获其他变量
- [this] 捕获当前类中的this指针,让lambda表达式拥有和当前类成员函数同样的访问权限
可以捕获局部变量,成员变量,全局变量等
int main()
{
int a = 10, b = 20;
auto f1 = [] {return a; }; // 错误,没有捕获外部变量,因此无法访问变量 a
auto f2 = [&] {return a++; }; // 正确,使用引用的方式捕获外部变量,可读写
auto f3 = [=] {return a; }; // 正确,使用值拷贝的方式捕获外部变量,可读
auto f4 = [=] {return a++; }; // 错误,使用值拷贝的方式捕获外部变量,可读不能写
auto f5 = [a] {return a + b; }; // 错误,使用拷贝的方式捕获了外部变量 a,没有捕获外部变量 b,因此无法访问变量 b
auto f6 = [a, &b] {return a + (b++); }; // 正确,使用拷贝的方式捕获了外部变量 a,只读,使用引用的方式捕获外部变量 b,可读写
auto f7 = [=, &b] {return a + (b++); }; // 正确,使用值拷贝的方式捕获所有外部变量以及 b 的引用,b 可读写,其他只读
return 0;
}
捕获方式有值捕获(按值复制外部变量),引用捕捕获(通过引用捕获外部变量),混合捕获(同时使用值捕获与引用捕获)
一般情况下,不指定lambda表达式的返回值,编译器会根据return语句自动推导返回值类型,但是需要注意的是lambda表达式不能通过列表初始化自动推导出返回值类型。
Lambda表达式的优点
- 可以直接在需要调用函数的位置定义短小精悍的函数,而不需要预先定义好函数
- 使用Lamdba表达式变得更加紧凑,结构层次更加明显、代码可读性更好
Lambda表达式的缺点
- Lamdba表达式语法比较灵活,增加了阅读代码的难度
- 对于函数复用无能为力