lambda表达式表示一个可调用的代码单元。我们可以认为它是一个未命名的内联函数。表达式形式如下:
[capture list] (parameter list) -> return type { function body }
capture list(捕获列表):lambda所在函数中的局部变量,供function body使用;
parameter list(参数列表):同普通函数;
return type(返回值):同普通函数,这个写法与普通函数不同,它是在函数尾部使用->;
function body(函数体):同普通函数。
我们可以忽略参数列表(等价于参数列表为空)和返回值(由类型推导来决定),但是捕获列表和函数体必须写。简单写法如下:
auto func = [] {
return 12;
};
std::cout << func() << std::endl;
稍微复杂一点的写法:
auto func = []() -> int {
return 12;
};
打印vector所有成员:
std::vector<std::string> vs;
vs.push_back("what");
vs.push_back("are");
vs.push_back("you");
vs.push_back("doing");
std::for_each(vs.begin(), vs.end(), [](const std::string &str) {
std::cout << str << " ";
});
按字符串长短稳定的排序:
std::stable_sort(vs.begin(), vs.end(), [](const std::string &left, const std::string &right) {
return left.size() < right.size();
});
加法:
auto addFunc = [](int i, int j) {
return i + j;
};
std::cout << addFunc(100, 200) << std::endl;
与普通函数不同,lambda不能有默认参数,也就是说形参和实参数目相等。
使用捕获列表:
1.值捕获,前提是变量可以拷贝,它不影响变量的原始值。
打印大于100的数
void func(const std::vector<int> &vi)
{
int dst = 100;
std::for_each(vi.begin(), vi.end(), [dst](int i) {
if (i > dst) {
std::cout << i << " ";
}
});
}
其中dst就是捕获的局部变量。2.引用捕获与引用变量一样,在lambda执行的时候必须保证被引用的对象存在。如果lambda在函数结束后执行,捕获的引用指向的局部变量已经销毁了。
在lambda表达式中修改一个捕获的局部变量
void func()
{
int dst = 100;
auto f = [&dst] {
dst = 200;
};
f();
std::cout << dst << std::endl;
}
结果是200
3.使用this捕获成员变量
class Test
{
public:
Test(int number) : number_(number) { }
void print()
{
auto f = [this] {
std::cout << number_ << std::endl;
};
f();
}
private:
int number_;
};
4.隐式捕获
[&] 采用引用的方式进行隐式捕获,lambda体中所捕获的局部变量都是引用捕获;
[=] 采用值拷贝的方式进行隐式捕获,lambda体中所捕获的局部变量都是值捕获;
[&, identifier_list] identifier_list是一个逗号分隔的列表,包含0个或多个来自所在函数的变量。这些变量采用值捕获方式,而任何隐式捕获的变量都采用引用方式捕获。即,identifier_list中的名字前面不能使用&。
[=, identifier_list] identifier_list中的变量都采用引用方式捕获,而任何隐式捕获的变量都是采用值方式捕获。identifier_list中的名字不能包含this,且这些名字之前必须使用&。
可变lambda
默认情况下,对于一个值捕获的变量lambda不会改变其值,编译也是通不过的。
但是有时候确实有这样的需求,那么必须在参数列表后面加上mutable,此时的参数列表不能省略,如下:
void func()
{
int i = 0;
auto f = [i] () mutable {
++i;
std::cout << i << std::endl;
};
f();
std::cout << i << std::endl;
}
输出1和0。虽然lambda改变了i的值,但也只是对lambda有效,在外部i的值还是为0,这样也与值捕获吻合。当然如果外部想使用改变后的值可以对它进行return,或者使用引用捕获。