lambda表达式
本页面不会为大家讲解C++中lambda表达式的详细底层原理, 只会讲解在特定场合如何使用lambda表达式, 本文秉承着让大家学会如何使用lambda表达式的主旨。 如果对于lambda表达式底层原理感兴趣, 可以自行上网搜索其他相关资料。
注意
按理来说,只要不写出非常刁钻的代码, 可以在不理解底层原理的情况下使用常规的lambda表达式写法可以满足绝大多数应用场景。
如果使用lambda表达式过程中出现了意料之外的CE等错误, 请改用传统函数实现, 不要创死在lambda表达式上, 浪费比赛时间。
lambda表达式的应用场景
在算法竞赛中,我们经常会把大篇幅的重复代码封装成函数, 以此来省去编写重复的代码,
在这个时候,如果我们要实现在一个函数中使用一些其他变量, 我们会使用传参的方式来实现。 例如:
但是如果我们要同时使用多个函数外的变量该怎么办呢? 传多个变量显然的,而且显然是非常麻烦的。 如果你又不喜欢开全局变量,那么就可以使用lambda表达式了。如何使用lambda表达式
你可以把lambda表达式理解成一个函数中的函数。
一个lambda表达式大概长这样:
auto是类型推到关键字,建议无脑写auto。以下是一个例子:
这样我们就可以实现在函数中声明一个lambda并且调用了!但是在这个时候我们发现在函数里面是不可以调用外面的变量的, 这个时候就要用到捕获了。
捕获的区别
捕获,顾名思义,就是把lambda外的变量捕获, 使其能够在lambda内部使用。
按引用捕获
按引用捕获,顾名思义,就是我们把这个变量以引用的方式捕获进来了, 具体方法是在中括号中加一个 “&”即可。
众所周知引用是一种起别名, 这样一来我们就可以在lambda内部以引用的方式使用外部的变量。
void NeverSayNever() {
int a = 4;
auto work = [&](){
cout << a << endl;
a = 1;
};
work();
cout << a << endl;
}
例如在上述的例子中,work()函数执行完之后输出的是1。
按值捕获
理解了按引用捕获之后,按值捕获就是只把这个数字捕获进来了, 一定要注意的是,你可在函数中使用按值捕获的东西来计算, 但是不能更改这个按值捕获的值。
写法是在中括号中写 "="。
void NeverSayNever() {
int a = 4;
auto work = [=](){
cout << a << endl;
//a = 1; //尝试修改的行为会报错
int b = a;//可以使用
};
work();
cout << a << endl;
}
如何使用lambda实现递归?
先上一段示例:
void NeverSayNever() {
auto dfs = [&](auto self,int x)->void{
if(x == 5) return;
cout << x << endl;
self(self,x + 1);
};
dfs(dfs,0);
}
//这段代码的输出结果:
//0
//1
//2
//3
//4
-
在参数列表中加入一个 "auto self"
-
在参数后用 " -> 返回值类型 " 来声明返回值类型
-
在lambda内部调用递归时,写self(self,……)
-
在调用lambda时 ”auto self“ 参数直接传入函数名
不需要知道为什么,只需要记住以上几点就可以了, 如果想知道底层原理可以去网上找资料学习, 本文不再赘述。
关于lambda递归的拓展
在使用lambda进行递归时,除了加一个"(auto self)", 还可以使用如下写法:
void NeverSayNever() {
function<void(int)> dfs = [&](int x){
if(x == 5) return;
cout << x << endl;
dfs(x + 1);
};
dfs(5);
}
不过这段代码省去了"auto self", 也不用在函数内使用"self(self,……)"写法。
只需要把自动推断类型的auto换成"function
可以自由选择喜欢的写法。
useless
捕获还有一种用法如下:
void NeverSayNever() {
int a = 2;
int b = 3;
int c = 4;
auto work = [=,&a,&c](){
a = 3;
c = 5;
cout << b << endl;
//b = 2; //报错 因为b是按值捕获
};
work();
}
}
日志
本页面创建于 2024/6/23 2:20