一直想写一篇文章,来总结lambda表达式,但是之前感觉总结的不是特别到位,现在看了几篇文章和视频后,感觉对lambda表达式有了比较深刻的认识,现在进行记录总结如下:
lambda表达式又叫做匿名函数,lambda表达式本质是一个匿名类,lambda为了我们能更方便的定义出一个函数方法提供了便利,下面咱们开始介绍下lambda表达式。
1.lambda表达式的引出
首先我们想完成一个 Add的函数,这个函数有个功能,就是把自己成员变量的值num_,和传进来的参数x相加,并且返回。我们一般用C++的写法如下:
#include<typeinfo>
#include<iostream>
#include<functional>
using namespace std;
class Cal{
public:
Cal(int num):num_(num){
cout<<"num_ :"<<num_<<endl;
};
int Add(int x){
cout<<"x+num_:"<<x+num_<<endl;
return x+num_;
};
private:
const int num_;
};
int main(){
Cal temp(5);
temp.Add(3);
return 0;
}
编译并且执行程序:
zhc@ubuntu:~/test/linux$ g++ -std=c++14 test.cpp -o test && ./test
num_ :5
x+num_:8
接下来我们用仿函数来实现,仿函数也就是重载小括号 ()的类,我们修改代码如下:
#include<memory>
#include<typeinfo>
#include<iostream>
#include<functional>
using namespace std;
class Cal{
public:
Cal(int num):num_(num){
cout<<"num_ :"<<num_<<endl;
};
int operator () (int x){
cout<<"x+num_:"<<x+num_<<endl;
return x+num_;
}
private:
const int num_;
};
int main(){
Cal Add(5);
Add(3);
return 0;
}
编译并且输出结果:
zhc@ubuntu:~/test/linux$ g++ -std=c++14 test.cpp -o test && ./test
num_ :5
x+num_:8
也就是说如果我们想实现一个简单的Add函数,也要定义一个类,或者用成员函数实现,或者用仿函数实现,有没有一种写法上更简单的方式呢,省略掉类的定义,那么我们的主角就要登场了,就是lambda表达式.看如下代码:
#include<memory>
#include<typeinfo>
#include<iostream>
#include<functional>
using namespace std;
int main(){
int num=5;
auto lam_add=[num](int x) ->int {
cout<<"num+x:"<<num+x<<endl;
return num+x;
};
lam_add(3);
return 0;
}
输出结果如下:
zhc@ubuntu:~/test/linux$ g++ -std=c++14 test.cpp -o test && ./test
num+x:8
正如我们的lambda表达式结果看,这个跟我们刚才写的仿函数类也是基本相同的,实际上我写的第二个例子,就是这个lambda表达式在调用的时候,生成的临时类对象,所对应的类的定义,
注意我的成员变量的写法,const int num_,这个是我故意这么写的,因为确实等价方式就是这样。下面我们来讲一讲lambda表达式的捕获列表,以及不同捕获形式,在生成类的成员函数里的可读可写属性。
2. lambda表达式的捕获列表
lambda表达式的书写形式如下:
[captrue] (params) opt -> ret {body};
其中,capture是捕获列表;params是参数列表;
opt是函数选项(const,mutable,noexcept等关键字);
ret是返回值类型;body是函数体。
lambda表达式可以通过捕获列表捕获一定范围内的变量:
[]不捕获任何变量;
[bar]按值捕获bar变量,同时不捕获其他变量,并作为副本在函数体使用(按值捕获);
[&bar]按引用捕获bar变量,同时不捕获其他变量;并作为引用在函数体使用(按引用捕获);
[=]捕获外部作用域作用变量,并作为副本在函数体使用(按值捕获);
[&]捕获外部作用域所有变量,并作为引用在函数体使用(按引用捕获);
[=,&foo]按值捕获外部作用域所有变量,并按引用捕获foo变量;
[this]捕获当前类中的this指针,让lambda拥有和当前类成员函数同样的访问权限,如果已经使用了&或者=,就默认添加此选项。捕获this的目的是可以在lambda中使用当前类的成员函数和成员变量。
一般,不会捕获全局变量,静态全局变量,局部静态局部变量,静态成员变量。
下面我们按照按值捕获和按引用捕获来说明下,捕获后在生成的匿名类里的成员变量情况,与外部变量的可写属性是否相同,以及是否能够改变外部变量。
下面咱们看下具体的例子:
这个图是我从别的地方copy过来的,暂时粘贴这里,后期再敲试验代码。
如果我们想改变这个 m,p的可写属性,可以在 lambda表达式中加入mutalbel关键字。
我画红线的部分,是原文书写错误,应该是有mutable时。
这里强调一点,这个 const int n,在用这个mutable以后,那么对应的成员变量还是 const int n ,也就是说这个属性,是拿 mutable改变不了的。