lambda表达式

lambda表达式

lambda表达式可以构造一个闭包,能够捕获当前作用域变量的无名函数对象。

使用lambda可以就地的定义一个目标函数,不需要额外的再写一个命名函数或者函数对象

  • 函数对象:在类中重载函数调用符(),此时类的对象就能像普通函数一样调用,因此取名为函数对象,同时它也可以称之为仿函数。如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
using namespace std;

class A{
public:
A(int _a, int _b):a(_a),b(_b){}

int operator() (){ //重载() 运算符
cout<<"a = "<<a<<" b = "<<b<<endl;
return a + b;
}
private:
int a;
int b;
};

int main()
{
A a(4, 6);
cout<<a()<<endl; //对象可以像普通函数一样使用
return 0;
}

lambda实现原理

lambda在编译时会自动的生成一个匿名类,捕获列表捕获的元素在匿名类创建时会拷贝进匿名类的private中,并且在该类重载了()运算符,大致如下:

1
2
3
4
5
int a = 2;
int b = 3;
auto fun = [=]() -> int {
return a + b;
}

对应的类为:

1
2
3
4
5
6
7
8
9
10
class Fun{
public:
Fun(int _a, int _b):a(_a),b(_b){}
int operator() ()const{ //如果上面使用了关键词 mutable,则函数不为const
return a + b;
}
private:
int a;
int b;
};

其中函数名由编译器决定,私有成员变量由捕获列表决定,重载()操作符函数里的内容由 lambda 表达式中的函数体决定,返回值由尾随返回类型决定或者自动进行推算。

lambda表达式声明

完整声明

1
[捕获] (参数列表) 说明符 约束(可选) -> 返回类型 { 函数体 }

省略了返回值类型,编译器可通过以下规则推断出表达式的返回类型:

  • 函数体中的return语句
  • 如果函数体没有return语句,则返回值为void
1
[捕获] (参数列表) { 函数体 }

省略形参列表:函数不接收实参,如同形参列表是 ()

1
[捕获] { 函数体 }

lambda捕获类型

  • [] 不捕获任何变量
  • [=] 以复制的方式捕获所有变量
  • [&] 以引用方式捕获所有变量
  • [var] 以复制的方式捕获标识符为var的变量
  • [&var] 以引用的方式捕获标识符为var的变量
  • [var…] 以包展开的方式复制参数包变量
  • [&var…] 以包展开的方式引用参数包变量
  • [=,&var] 标识符为var的变量以引用的方式捕获,剩余其他变量以复制的方式捕获
  • [&,var] 标识符为var的变量以复制的方式捕获,剩余其他变量以引用的方式捕获
  • [this] 以引用的方式捕获当前对象
  • [*this] 以复制的方式捕获当前对象

lambda使用

常用捕获

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>

using namespace std;

int main()
{
int a = 3,b = 4;
string c = "lambda";
float d = 5.754;

auto fun = [=]{ //以复制的方式捕获当前作用域的所有变量
//a = 44; //没加 mutable 会报错
printf("1: a = %d b = %d c = %s d = %.3f\n",a,b,c.c_str(),d);
};
fun();

auto fun1 = [&]{ //以复制的方式捕获当前作用域的所有变量
a = 30;
b = 40;
c = "lambda test";
d = 1.23455;
printf("2: a = %d b = %d c = %s d = %.5f\n",a,b,c.c_str(),d);
};
fun1();

auto fun2 = [a, b, &c, &d] () mutable { //a,b以复制的方式捕获c,d以引用的方式捕获
a = 300;//加了 mutable 说明符 可以修改复制方式捕获的值,但不会影响到原有的值
b = 400;
c = "lambda test test";
d = 11.23455;
printf("3: a = %d b = %d c = %s d = %.5f\n",a,b,c.c_str(),d);
};
fun2();
printf("4: a = %d b = %d c = %s d = %.5f\n",a,b,c.c_str(),d);//a,b的值没有改变

return 0;
}

输出

1
2
3
4
1: a = 3 b = 4 c = lambda d = 5.754
2: a = 30 b = 40 c = lambda test d = 1.23455
3: a = 300 b = 400 c = lambda test test d = 11.23455
4: a = 30 b = 40 c = lambda test test d = 11.23455

捕获参数包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
using namespace std;

void tprintf(int i) //这个函数必须定义 tprintf函数的参数包解析完后,就会调用void tprintf(int i)
{
cout<<"i = "<<i<<" end"<<endl;
return;
}

template<typename U, typename ...Ts>
void tprintf(int i, U u, Ts... ts)
{
auto t = [i, ts...](){ //lambda 捕获参数包
tprintf(i + 1, ts...);
};
std::cout <<"i = "<<i<<" value is " << u << std::endl;
t();
return ;
}

int main()
{
tprintf(1, 1, 'c', 3, 8, "sda", "jjhj");

int a = 3;
int b = 4;
int c = 5;
auto f = [](){
cout<<"lambda"<<endl;
};

return 0;
}

输出

1
2
3
4
5
6
7
i = 1 value is 1
i = 2 value is c
i = 3 value is 3
i = 4 value is 8
i = 5 value is sda
i = 6 value is jjhj
i = 7 end

捕获对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream>
using namespace std;

class Lam{
public:
Lam(int _miA, int _miB):miA(_miA),miB(_miB){}
~Lam(){}

void lamTest();

void printfAB(int index) const {
cout<<index<<": miA = "<<miA<<" miB = "<<miB<<endl;
}

void setAB(int miA, int miB){
this->miA = miA;
this->miB = miB;
}
private:
int miA;
int miB;
};

void Lam::lamTest()
{
auto f = [*this] {
this->printfAB(1); //以复制的方式捕获对象时,如果没加 mutable标识符 只能调用 存在const标识符的 函数
//setAB(5, 6); //编译不过
};
f();

auto f1 = [*this]() mutable{ //加了mutable标识符 编译器生成的 访函数就不为const
miA = 3;
miB = 4;
this->printfAB(2);
this->setAB(5, 6); //加了mutable标识符 可以调用非const函数
this->printfAB(3);
};
f1();

this->printfAB(4);//以复制的方式捕获对象 不会对原有对象产生影响

auto f2 = [this]{//以引用的方式捕获对象
miA = 7;
miB = 8;
this->printfAB(5);
};
f2();
}

int main()
{
Lam lam(1,2);
lam.lamTest();
lam.printfAB(6);//f2以引用的方式捕获对象 对原有对象产生了影响
return 0;
}

输出

1
2
3
4
5
6
1: miA = 1 miB = 2
2: miA = 3 miB = 4
3: miA = 5 miB = 6
4: miA = 1 miB = 2
5: miA = 7 miB = 8
6: miA = 7 miB = 8

使用场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream>
#include <map>
#include <functional>
#include <vector>
#include <algorithm>
using namespace std;

void lambdaSwitch() //使用lambda代替switch
{
map<int,std::function<string()>> lam;
lam[1] = []{return "lambda1";};
lam[2] = []{return "lambda2";};
lam[3] = []{return "lambda3";};

printf("1: %s\n",lam[1]().c_str());
printf("2: %s\n",lam[2]().c_str());
printf("3: %s\n",lam[3]().c_str());
}

class SortTest;
typedef vector<SortTest> SortTestSet;
class SortTest{
public:
SortTest(int _miId, string _msName):miId(_miId),msName(_msName){}
~SortTest(){}

inline int getId() const{return miId;};
inline string getName() const{return msName;};
private:
int miId;
string msName;
};
void lambdaSort() //lambda表达式 用于排序
{
SortTestSet set;
set.push_back(SortTest(5, "sort"));
set.push_back(SortTest(15, "sortsortsort"));
set.push_back(SortTest(7, "sortsortsortsortsort"));
set.push_back(SortTest(2, "sortsortsortsort"));
set.push_back(SortTest(4, "sortsort"));

sort(set.begin(), set.end(), [](SortTest a, SortTest b){
//return a.getId() < b.getId();//按照 miId的大小排序
return a.getName() < b.getName();//按照 msName的长度排序
});

for(auto s:set){
cout<<"sort: id = "<<s.getId()<<" name = "<<s.getName()<<endl;
}
}

int main()
{
lambdaSwitch();
lambdaSort();
return 0;
}

输出

1
2
3
4
5
6
7
8
1: lambda1
2: lambda2
3: lambda3
sort: id = 5 name = sort
sort: id = 4 name = sortsort
sort: id = 15 name = sortsortsort
sort: id = 2 name = sortsortsortsort
sort: id = 7 name = sortsortsortsortsort
#
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×