STL:lambda 表达式
记录 lambda 的参数、捕获列表、返回类型和可变状态,并说明它与泛型算法的配合方式。
lambda表达式概览
可以向算法传递任何类型的可调用对象,这其中包括函数,函数指针,还有重载了调用运算符()的类,以及lambda表达式。lambda表达式的行为类似于函数,可以对其使用调用运算符和传递参数。lambda表达式的一般结构为:
[捕获列表] (参数列表) -> 返回类型{函数体}
可以忽略返回类型和参数列表。当忽略返回类型时,返回类型根据return的类型自动推断,否则类型为void。不加()表明忽略参数列表,等价于指定一个空参数列表(空括号)。
auto f = [] { return 42; };
向lambda传递参数
参数列表括号中可以添加对lambda传递的参数。
//一个具有比较功能的lambda表达式
auto f = [](const int& a, const int& b) { return a < b; };
//使用lambda表达式的sort
sort(vec.begin(), vec.end(), f);
使用捕获列表
空捕获列表表示不会使用表达式所在函数中的任何参数。可以在参数列表中给定所需参量,该参量必须在表达式之前声明。
int ve = 5;
auto f = [ve](const int& a) { return a < ve; };
可以传递多个参量,之间使用逗号隔开:
int ve, i;
auto f = [ve, i](const int& a) { return a + i < ve; };
lambda的捕获和返回
值捕获和引用捕获
[ve] { return ve; }; //值捕获
[&ve] { return ve; }; //引用捕获
使用引用捕获必须保证在语句执行时引用仍然存在。如果捕获了迭代器,迭代器很有可能在语句执行时失效。
隐式捕获
可以向[]中传递=或者&来表示捕获的类型,这样当语句中出现函数中的变量时,它将遵循赋值或引用。可以不显示告知捕获类型。
[&](const int& a) { b++; };
[=](const int& a) { return a < b; };
可以使用混合类型,指定特定的捕获为特定类型。
[=, &b]() { return b < c; };
[&, b]() { return b < c; };
如果默认类型为引用,显示指定的类型必须为赋值,即不能有[&, &b]() { return b < a; }存在,赋值也一样。
可变lambda
拷贝的捕获不能修改值(并不是像函数的临时变量一样不会影响原始变量,编辑器直接禁止此类操作)。若要在函数中修改其值(函数外该值仍然未变,这一点不同于引用捕获),需使用关键字mutable。
mutable有用情不专一的意思,真是笑死。
[b]() mutable{ return ++b; };
//执行后,lambda表达式中的b++,然而上一级函数中的b未变。
指定lambda的返回类型
lambda可以通过return自动推断返回类型,但当函数体中不仅仅存在return语句时,lambda自动返回void,此时需要显式指定返回类型。lambda使用->来指出返回的数据类型。
[](int a, int b) -> bool { if (a + b < 1) return true;
else return false; };