[外部变量访问方式说明符] (参数) mutable noexcept/throw() -> 返回值类型
{
函数体;
};
2) (参数)所谓外部变量,指的是和当前 lambda 表达式位于同一作用域内的所有局部变量。
-> 返回值类型。比如,如下就定义了一个最简单的 lambda 匿名函数:其中,红色标识的参数是定义 lambda 表达式时必须写的,而绿色标识的参数可以省略。
[]{}
显然,此 lambda 匿名函数未引入任何外部变量([] 内为空),也没有传递任何参数,没有指定 mutable、noexcept 等关键字,没有返回值和函数体。所以,这是一个没有任何功能的 lambda 匿名函数。| 外部变量格式 | 功能 |
|---|---|
| [] | 空方括号表示当前 lambda 匿名函数中不导入任何外部变量。 |
| [=] | 只有一个 = 等号,表示以值传递的方式导入所有外部变量; |
| [&] | 只有一个 & 符号,表示以引用传递的方式导入所有外部变量; |
| [val1,val2,...] | 表示以值传递的方式导入 val1、val2 等指定的外部变量,同时多个变量之间没有先后次序; |
| [&val1,&val2,...] | 表示以引用传递的方式导入 val1、val2等指定的外部变量,多个变量之间没有前后次序; |
| [val,&val2,...] | 以上 2 种方式还可以混合使用,变量之间没有前后次序。 |
| [=,&val1,...] | 表示除 val1 以引用传递的方式导入外,其它外部变量都以值传递的方式导入。 |
| [this] | 表示以值传递的方式导入当前的 this 指针。 |
【例 1】lambda 匿名函数的定义和使用。注意,单个外部变量不允许以相同的传递方式导入多次。例如 [=,val1] 中,val1 先后被以值传递的方式导入了 2 次,这是非法的。
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int num[4] = {4, 2, 3, 1};
//对 a 数组中的元素进行排序
sort(num, num+4, [=](int x, int y) -> bool{ return x < y; } );
for(int n : num){
cout << n << " ";
}
return 0;
}
程序执行结果为:
1 2 3 4
程序第 9 行通过调用 sort() 函数实现了对 num 数组中元素的升序排序,其中就用到了 lambda 匿名函数。而如果使用普通函数,需以如下代码实现:
#include <iostream>
#include <algorithm>
using namespace std;
//自定义的升序排序规则
bool sort_up(int x,int y){
return x < y;
}
int main()
{
int num[4] = {4, 2, 3, 1};
//对 a 数组中的元素进行排序
sort(num, num+4, sort_up);
for(int n : num){
cout << n << " ";
}
return 0;
}
此程序中 sort_up() 函数的功能和上一个程序中的 lambda 匿名函数完全相同。显然在类似的场景中,使用 lambda 匿名函数更有优势。
#include <iostream>
using namespace std;
int main()
{
//display 即为 lambda 匿名函数的函数名
auto display = [](int a,int b) -> void{cout << a << " " << b;};
//调用 lambda 函数
display(10,20);
return 0;
}
程序执行结果为:
10 20
可以看到,程序中使用 auto 关键字为 lambda 匿名函数设定了一个函数名,由此我们即可在作用域内调用该函数。
#include <iostream>
using namespace std;
//全局变量
int all_num = 0;
int main()
{
//局部变量
int num_1 = 1;
int num_2 = 2;
int num_3 = 3;
cout << "lambda1:\n";
auto lambda1 = [=]{
//全局变量可以访问甚至修改
all_num = 10;
//函数体内只能使用外部变量,而无法对它们进行修改
cout << num_1 << " "
<< num_2 << " "
<< num_3 << endl;
};
lambda1();
cout << all_num <<endl;
cout << "lambda2:\n";
auto lambda2 = [&]{
all_num = 100;
num_1 = 10;
num_2 = 20;
num_3 = 30;
cout << num_1 << " "
<< num_2 << " "
<< num_3 << endl;
};
lambda2();
cout << all_num << endl;
return 0;
}
程序执行结果为:
lambda1:
1 2 3
10
lambda2:
10 20 30
100
当然,如果我们想在 lambda1 匿名函数的基础上修改外部变量的值,可以借助 mutable 关键字,例如:感兴趣的读者,可自行尝试在 lambda1 匿名函数中修改 num_1、num_2 或者 num_3 的值,观察编译器的报错信息。
auto lambda1 = [=]() mutable{
num_1 = 10;
num_2 = 20;
num_3 = 30;
//函数体内只能使用外部变量,而无法对它们进行修改
cout << num_1 << " "
<< num_2 << " "
<< num_3 << endl;
};
由此,就可以在 lambda1 匿名函数中修改外部变量的值。但需要注意的是,这里修改的仅是 num_1、num_2、num_3 拷贝的那一份的值,真正外部变量的值并不会发生改变。
#include <iostream>
using namespace std;
int main()
{
auto except = []()throw(int) {
throw 10;
};
try {
except();
}
catch (int) {
cout << "捕获到了整形异常";
}
return 0;
}
程序执行结果为:
捕获到了整形异常
可以看到,except 匿名数组中指定函数体中可以抛出整形异常,因此当函数体中真正发生整形异常时,可以借助 try-catch 块成功捕获并处理。
#include <iostream>
using namespace std;
int main()
{
auto except1 = []()noexcept{
throw 100;
};
auto except2 = []()throw(char){
throw 10;
};
try{
except1();
except2();
}catch(int){
cout << "捕获到了整形异常"<< endl;
}
return 0;
}
此程序运行会直接崩溃,原因很简单,except1 匿名函数指定了函数体中不发生任何异常,但函数体中却发生了整形异常;except2 匿名函数指定函数体可能会发生字符异常,但函数体中却发生了整形异常。由于指定异常类型和真正发生的异常类型不匹配,导致 try-catch 无法捕获,最终程序运行崩溃。
如果不使用 noexcept 或者 throw(),则 lambda 匿名函数的函数体中允许发生任何类型的异常。
版权说明:Copyright © 广州松河信息科技有限公司 2005-2025 版权所有 粤ICP备16019765号
广州松河信息科技有限公司 版权所有