最近在开发过程中,经常使用到lambda表达式,之前也看过相关的东西,但总感觉用起来有点模糊,所以这次系统的总结下lambda相关东西。
lambda表达式是C++11的新特性之一,为了更深层次的研究lambda表达式,以下通过代码实验和查阅相关文档进行了详细说明。
lambda函数的语法定义如下:
[capture] (parameter)mutable ->return-type{statement}
[capture]:捕获列表,捕获列表能够捕捉上下文中的变量以供lambda函数使用。但需要注意的是,它捕获的上下文只能是出于父作用域中,后续会详细进行说明。
(parameter):参数列表。与普通函数的参数列表移植,如果不需要参数传递,则可以连通()一起省略。
mutable:在默认情况下,lambda函数是一个const函数,加入mutable可以取消其常量性,这个设计到了lambda函数的实现原理,后续会对其进行说明。当使用该修饰符的时,参数列表不可以省略(及时参数为空)。
->return-type:返回类型。
{statement}:函数体,和普通函数一样,除了可以使用参数外,还可以使用所有捕获的变量。
如下都是一个lambda函数:
(1)[]{}
(2)auto fun = [&]{int a}{b=a};
接下来我们根据(2)的形式依次介绍下lambda函数。
1. []
捕获列表,捕获列表里面的内容,首先必须确定的是父作用域中的上下文。对于全局变量和静态变量,它是不能捕获的。如:
#include<iostream>
using namespace std;
int qwe = 300;
void main()
{
auto fun2 = [&qwe]()
{
qwe = 500;
};
cout << qwe << endl;
system("pause");
}
这个时候是报错的,编译就会报错,提示不能捕获静态变量值。
但我们改为:
void main()
{
auto fun2 = []()
{
qwe = 500;
};
cout << qwe << endl;
system("pause");
}
它这个时候编译和运行都没问题,打印值也为500,这个问题也困扰了半天,为啥我们显式捕获全局变量不能捕获,但我们去掉&就可以捕获了。这个问题我的思考是这样的:
对于lambda的底层实现来说,lambda的底层实现就是仿函数,仿函数其实就是重定义了成员函数operator()的一种自定义类型对象,对于一个lambda来说,它对应的仿函数是这样的:
class lambdafun
{
public:
lambdafun(捕获变量)
{
捕获值=捕获变量;
}
public:
type operator(parameter)()const
{
函数体。
}
private:
捕获值。
}
它对应的lambda函数如下:
[捕获值](parameter)->return type
{
函数体;
}
有了这样的对应的关系以后,我们理解这个问题就好理解多了,对于捕获值的类型,lambda现在只支持对父作用域的捕获,对于全局变量或静态变量,因为内存区域所处不同,lambda内部会对其进行一个过滤,对于全局变量直接过滤掉,相当于我们仿函数没有成员变量,但是全局变量对于我们的operator()函数体内是可以查找到的一个变量,所以这就是为啥不能显式捕获,但函数体却可以对其进行使用。
同时对于[]中为空的时候,我们表示不捕获任何东西。
[=]对应仿函数的构造函数参数为值传递,但因为operator()默认为const,不能对成员变量进行修改,所以当我们在函数体内部对捕获值进行修改的时候回报错。
[&]表示为引用传递,此时我们就可以对捕获值进行修改,至于为啥对于一个const成员函数值传递不可以修改,引用传递可以修改,这里暂时不叙述了,这个涉及到了引用的内部实现。
其实如果我们知道了lambda的内部实现就是一个仿函数以后,用lambda就会得心应手了。
lambda的一些注意点如下:
1.lambda函数相比于常规函数来说,更加直观,使用起来也非常简便,代码可读性也很好。同时lambda函数默认是内联的,运行效率也不差。同时也要注意捕获变量为值传递时,其传递的值在lambda函数定义的时候就已经决定了,而按引用传递的捕获变量,其传递的值等于lambda函数调用时候的值。
2.lambda的mutable我其实觉得是一个可以取消的东西,至少我觉得没有用处,相当于打破了const函数的作用,但同时这个值也传递不出来,没用。如:
int c = 10;
auto fun2 = [=]()mutable
{
c = 60;
};
fun2();
cout << c << endl;
system("pause");
打印得到的值为10;
3.同时lambda对于STL算法的使用会更加方便。如
vector<int> num;
for_each(num.begin(),num.end(),[&](int i)
{
if(i<10)
num.push_back(i);
});
先介绍到这。
C++11特性之lambda应用
最新推荐文章于 2022-09-30 22:05:22 发布