在 C++ 里,Lambda 表达式为我们提供了一种简洁、高效的方式来定义匿名函数,它能够让代码更加紧凑和灵活,尤其在一些需要临时定义函数逻辑的场景下。
(一)Lambda 表达式
Lambda 表达式的基本语法如下:
[ capture list ] (parameters) -> return_type { function body }
[ capture list ]:捕获列表,它决定了 Lambda 表达式能够访问哪些外部变量,以及以何种方式访问(按值捕获或引用捕获)。如果不需要访问外部变量,这里可以为空 []。
(parameters):参数列表,就像普通函数的参数一样,指定 Lambda 函数接受的输入参数。如果没有参数,括号也不能省略,写成 ()。
-> return_type:返回值类型指示符,用于明确 Lambda 函数的返回值类型。如果编译器能够自动推断返回值类型,这部分可以省略,让编译器自动完成推断工作。
{ function body }:函数体,包含了 Lambda 函数具体要执行的代码逻辑,与普通函数的函数体类似。
(二)示例
// 示例 1:无参数、无返回值,仅仅打印一条信息
auto fun3 = []() {cout << "[] ()" << endl; };
fun3();
// 示例 2:无参数,有返回值
auto fun5 = [] {cout << "fun 5 run" << endl; return 5; };
int num5 = fun5();
cout << num5 << endl;
// 示例 3:有参数,有返回值
auto fun1 = [](int a, int b) -> int { cout << a << " " << b << endl; return a * b; };
int num1 = fun1(2, 3);
cout << num1 << endl;
在示例 1 中,[]() 定义了一个无参数的 Lambda 表达式,函数体里只是简单地向控制台输出一条信息。调用 fun3() 就能执行这个匿名函数。
示例 2 同样无参数,但它有返回值。当调用 fun5() 时,先打印信息,然后返回值 5 被赋给 num5 并输出。
示例 3 是一个更常见的形式,接受两个整数参数 a 和 b,在函数体中先打印这两个参数,然后返回它们的乘积。通过 fun1(2, 3) 调用,传入实际参数 2 和 3,得到结果并输出。
(三)捕获外部变量
这可是 Lambda 表达式的一个关键特性,它让 Lambda 函数能够与外部环境进行交互。
1.按值捕获
int main()
{
Int a(10);
// 按值捕获 a,会用 a 拷贝构造一个副本,只可读,不可写
auto fun = [a](int x)->int {return a.GetValue() + x; };
int num = fun(10);
cout << num << endl;
}
这里定义了一个 Int 类型的变量 a,在 Lambda 表达式 [a](int x)->int {return a.GetValue() + x; } 中,[a] 表示按值捕获 a。这意味着 Lambda 函数内部使用的是 a 的一个副本,它不能修改外部原始的 a。当调用 fun(10) 时,将 a 的值(通过 GetValue 函数获取)与传入的参数 10 相加,返回结果。
2.引用捕获
int main()
{
Int a(10);
// 引用捕获不会建立副本,可读可写
auto funa = [&a](int x)->int
{
cout << a.GetValue() << endl;
a.SetValue(100);
return x + 10;
};
int c = funa(10);
cout << c << endl;
a.SetValue(200);
c = funa(10);
cout << c << endl;
}
在这个例子中,[&a] 采用引用捕获方式。此时,Lambda 函数内部操作的就是外部原始变量 a,可以读取它的值(通过 GetValue 打印),也能修改它的值(通过 SetValue)。第一次调用 funa(10),修改 a 的值为 100,后续再次修改 a 为 200 并重新调用 funa,输出结果会随之变化,充分体现了引用捕获的特性。
3.混合捕获
int main()
{
Int valx(10);
Int* thiz = &valx;
auto fun = [thiz, valx] {
cout << "&valx:" << &valx << endl;
thiz->GetValue();
thiz->SetValue(100);
};
fun();
cout << "&valx:" << &valx << endl;
cout << valx << endl;
}
这里出现了混合捕获,[thiz, valx] 既按值捕获了 valx,又捕获了指向 valx 的指针 thiz。在 Lambda 函数内部,可以打印 valx 的地址(虽然是副本的地址),通过指针 thiz 操作原始的 valx 对象,调用 GetValue 和 SetValue 函数。执行完 Lambda 函数后,再打印外部原始 valx 的地址和值,能清晰看到值已经被 Lambda 函数内部通过指针修改。
(四)全局变量与 Lambda
Int tmp(10);//全局作用域不存在捕获
void func()
{
tmp.SetValue(100);
}
int main()
{
cout << tmp.GetValue() << endl;
auto funa = []() { cout << tmp.GetValue() << endl; };
}
这里定义了全局变量 tmp,在 main 函数中的 Lambda 表达式如果想要访问它,可以直接在捕获列表为空的情况下使用(前提是全局变量有合适的访问权限)。即当 Lambda 函数需要用到全局数据时,无需特别捕获,直接操作即可(要遵循作用域和访问规则)。
(五)总结
Lambda 表达式为 C++ 编程带来了极大的便利,让我们能在需要的地方快速定义小型、针对性强的函数逻辑。通过灵活运用捕获列表,能够精细控制与外部环境的交互方式,无论是按值捕获保证数据只读性,还是引用捕获实现实时数据共享与修改,亦或是混合捕获满足复杂需求,都让代码更加简洁高效。

被折叠的 条评论
为什么被折叠?



