目录
Lambda 表达式是 C++11 引入的一种匿名函数的方式,它允许你在需要函数的地方内联地定义函数,而无需单独命名函数。
函数结构
Lambda 表达式的基本语法如下:
[capture clause](parameters) -> return_type {
// 函数体
// 可以使用捕获列表中的变量
return expression; // 可选的返回语句
}
Lambda 表达式由以下部分组成:
- 捕获列表(Capture clause):用于捕获外部变量,在 Lambda 表达式中可以访问这些变量。捕获列表可以为空,也可以包含变量列表 [var1, var2, ...] 。
- 参数列表(Parameters):与普通函数的参数列表类似,可以为空或包含参数列表 (param1, param2, ...) 。
- 返回类型(Return type):Lambda 表达式可以自动推断返回类型auto,也可以显式指定返回类型 -> return_type 。如果函数体只有一条返回语句,可以省略返回类型。
- 函数体(Body):Lambda 表达式的函数体,包含需要执行的代码。
示例一
Lambda 表达式最简单的案例是在需要一个小型函数或临时函数时直接使用它。以下是一个非常简单的例子,其中使用 Lambda 表达式来定义一个加法操作,并立即使用它来计算两个数的和。
#include <iostream>
using namespace std;
/*
*
* [capture clause](parameters) -> return_type {
// 函数体
// 可以使用捕获列表中的变量
return expression; // 可选的返回语句
}
int add(int a,int b)
{
return a+b;
}
*/
int main()
{
int x = 10;
int y = 20;
auto add = [](int a,int b) -> int //括号里面为参数列表 箭头后面为返回值类型
{
return a+b;
};
int ret = add(x,y);
cout << "结果是:" << ret << endl;
return 0;
}
在这个例子中:
- 我们定义了一个名为 add 的 Lambda 表达式,它接受两个整数参数,并返回它们的和。
- 然后,我们使用这个 Lambda 表达式来计算两个数字(10 和 20)的和,并将结果存储在变量 sum中。
- 最后,我们打印出这个和。
示例二
我们可以写一个例子,其中使用一个函数来找出两个数中的较大数,这个函数将接受一个 lambda 函数作为回调来比较这两个数。Lambda 函数将直接在函数调用时定义,完全是匿名的。
先回忆下回调函数
#include <iostream>
using namespace std;
bool myCompare(int a,int b)
{
return a>b;
}
int getMax(int a,int b,bool(*compare)(int ,int ))
{
if(compare(a,b))
{
return a;
}else
{
return b;
}
}
int main()
{
int x = 66;
int y = 99;
// 回调函数
int max = getMax(x, y, myCompare);
cout << " The larger number is " << max << endl;
return 0;
}
使用匿名 Lambda 函数来返回两个数中的较大数
#include <iostream>
using namespace std;
// 函数,接受两个整数和一个比较的 lambda 函数
int getMax(int a,int b,bool(*compare)(int ,int ))
{
if(compare(a,b))
{
return a;
}else
{
return b;
}
}
int main()
{
int x = 66;
int y = 88;
// 直接在函数调用中定义匿名 lambda 函数
int max = getMax(x ,y ,[](int a,int b) -> bool
{
return a>b;
});
cout << " The larger number is " << max << endl;
return 0;
}
在这个例子中:
- getMax 函数接受两个整数 a 和 b ,以及一个比较函数 compare 。这个比较函数是一个指向函数的指针,它接受两个整数并返回一个布尔值。
- 在 main 函数中,我们调用 getMax ,并直接在调用时定义了一个匿名的 lambda 函数。这个 lambda 函数接受两个整数并返回一个表示第一个整数是否大于第二个整数的布尔值。
- 这个 lambda 函数在 getMax 中被用作比较两个数的逻辑。根据 lambda 函数的返回值, getMax 返回较大的数。
这个例子展示了如何直接在函数调用中使用匿名 lambda 函数,使代码更加简洁和直接。这种方法在需要临时函数逻辑的场合非常有用,尤其是在比较、条件检查或小型回调中。
在 Lambda 表达式中,参数捕获是指 Lambda 表达式从其定义的上下文中捕获变量的能力。这使得 Lambda 可以使用并操作在其外部定义的变量。捕获可以按值(拷贝)或按引用进行。
示例三
让我们通过一个简单的示例来展示带参数捕获的 Lambda 表达式。
使用带参数捕获的 Lambda 表达式
#include <iostream>
using namespace std;
int main()
{
int x = 20;
int y = 10;
// 捕获 x 和 y 以便在 Lambda 内部使用
// 这里的捕获列表 [x, y] 表示 x 和 y 被按值捕获
auto sum = [x,y]()
{
//x++;
//y++; 按值捕获,关注的是值本身,无法修改
return x+y;
};
cout << "Sum is " << sum() << endl;
cout << "x is now: " << x << ", y is now: " << y << endl << endl;
// 捕获所有外部变量按值捕获(拷贝)
int z = 30;
auto multiply = [=]()
{
// x++;
// y++; 按值捕获,关注的是值本身,无法修改
return x*y*z;
};
cout << "Product is: " << multiply() << endl;
cout << "x is now: " << x << ", y is now: " << y << endl << endl;
// 捕获所有外部变量按引用捕获
auto modifyAndSum = [&]()
{
x = 15; // 修改 x 的实际值
y = 25; // 修改 y 的实际值, 引用捕获可以修改
return x+y;
};
cout << "Modified Sum is: " << modifyAndSum() << endl;
cout << "x is now: " << x << ", y is now: " << y << endl;
return 0;
}
在这个例子中:
- 第一个 Lambda 表达式 sum 按值捕获了 x 和 y (即它们的副本)。这意味着 sum 内的 x 和 y 是在 Lambda 定义时的值的拷贝。
- 第二个 Lambda 表达式 multiply 使用 [=] 捕获列表,这表示它按值获捕所有外部变量。
- 第三个 Lambda 表达式 modifyAndSum 使用 [&] 捕获列表,这表示它按引用捕获所有外部变量。因此,它可以修改 x 和 y 的原始值。
这个示例展示了如何使用不同类型的捕获列表(按值和按引用)来控制 Lambda 表达式对外部变量的访问和修改。按值捕获是安全的,但不允许修改原始变量,而按引用捕获允许修改原始变量,但需要注意引用的有效性和生命周期问题。
附录
以下是一个表格,概述了 Lambda 函数和内联函数在 C++ 中的相似之处和区别:
特性
|
Lambda 函数
| 内联函数 |
定义
|
一种匿名函数,通常用于定义在需要它们的地方。
|
一种常规函数,通过
inline
关键字定义。
|
用途
|
提供一种快捷方式来定义临时的、小型的函数。
|
用于优化小型函数,减少函数调用的开销。
|
语法
|
使用
[capture](params) { body } 的形式定义。
|
使用常规函数定义语法,但在前面加上 inline 关键字。
|
生命周期
|
在定义它们的作用域内有效。
|
在整个程序执行期间有效。
|
捕获外部
变量
|
可以捕获外部作用域中的变量(按值或按引用)。
|
不能直接捕获外部变量,只能通过参数传递。
|
调用方式
|
作为函数对象,可直接调用。
|
像普通函数一样调用。
|
优化
|
可以被编译器自动内联化,但这取决于编译器优化策略。
|
明确请求编译器尝试内联,但实际内联化也取决于编译器。
|
可见性
| 通常只在定义它们的局部作用域内可见。 |
可以在定义它的任何作用域内可见。
|
使用场景
|
适合于一次性使用的场景,如作为回调、在算法中使用等。
|
适合于频繁调用的小型函数。
|
请注意,虽然 Lambda 函数和内联函数在某些方面有相似之处,如它们都可以被编译器优化以减少调用开销,但它们在设计和用途上有明显的不同。Lambda 函数的核心优势在于它们的匿名性和对外部变量的捕获能力,而内联函数则主要关注于提高小型函数的性能。