Lambda 表达式
Lambda 表达式,通常简称为“lambda”,是一种方便地以对象形式编写代码片段的方式,以便将其作为函数参数发送并稍后重用。Lambda 主要用于
- 在函数内部创建命名对象,这些对象可以像函数一样重用,而不会污染全局命名空间。
- 创建可以发送到其他函数(例如标准库算法)的“匿名”代码片段。
Lambda 通常被称为匿名函数、函数对象或函数符。这些名称都不完全正确,尽管在谈论 lambda 时可以使用它们。事实上,lambda 创建了一个不可见的对象,尽管它们本身只是表达式。由于 lambda 的工作方式(创建了一个神奇的、不可见的、未知类型的对象),要将它们分配给一个对象,我们需要使用关键字auto
,或者使用标准库类型——std::function
(我们将在课程后面学习它)。
语法

lambda 必须有一个主体,我们将在其中编写代码和一个捕获列表(可以为空)。参数列表是可选的,尽管经常使用。我们可以向 lambda 表达式添加各种其他内容,如属性、显式返回类型等,尽管它们既不是强制性的也不常用,所以我们将在课程后面讨论它们。
捕获列表
正如我们从函数课程中了解到的,局部变量(例如来自main
函数)在任何其他函数的主体中都是未知的。同样的情况也适用于 lambda 表达式。函数中的局部变量在 lambda 表达式内部是不可见的,这就是为什么它们需要被捕获在捕获列表中。
int five = 5;
auto get7 = [five] () { return five + 2; };
std::cout << get7();
7
如果 lambda 表达式的参数列表为空,则可以省略括号。
int five = 5;
auto get7 = [five] { return five + 2; };
std::cout << get7();
捕获列表中捕获的变量目前不能被修改。有一种方法可以做到这一点,但我们将在第二课中讨论。
参数列表
lambda 表达式中的参数列表就像我们从函数中了解到的那样工作。它允许我们声明 lambda 应该用哪些参数调用,然后将参数传递给它。
auto multplyBy7 = [] (int a) { return a * 7; }; // a lambda with a parameter of type int
std::cout << multplyBy7(5); // the lambda called with an argument 5
35
lambda 主体
一个我们已经知道的常规代码块。在这里我们声明变量,对对象进行操作等。我们可以在 lambda 主体内部使用return
语句。
简单示例
lambda 和每次调用都返回 5 的函数的比较
#include <iostream>
int main()
{
auto five = [] { return 5; };
std::cout << five();
}
#include <iostream>
int five()
{
return 5;
}
int main()
{
std::cout << five();
}
返回其参数的平方的 lambda
auto square = [](int x) { return x*x; };
std::cout << square(5);
25
用于代码重用的 Lambda
void print3Hellos(std::string name) {
auto print_hello = [name](std::string hello) {
std::cout << hello << ", " << name << "!\n";
}
print_hello("Hello");
print_hello("Welcome");
print_hello("Hi");
}
// ...
print3Hellos("Mark");
Hello, Mark!
Welcome, Mark!
Hi, Mark!
常见错误
尝试使用未捕获的变量
int main()
{
int A = 5;
// ❌ Variable A is not known inside addToA ❌
// auto addToA = [] (int b) { return A + b; };
// ✅ Proper lambda declaration ✅
auto addToA = [A] (int b) { return A + b; };
std::cout << addToA(5) << "\n";
}
尝试修改捕获的变量
int main()
{
int A = 5;
// ❌ We can't modify the variable A ❌
// auto addToA = [A] (int b) { A += b; };
// ✅ For now, we can make use of the fact that we can return values.
// You will learn how to modify captured variables later in the course. ✅
auto addToA = [A] (int b) { return A + b; };
std::cout << addToA(5) << "\n";
}
实际用法
我们建议使用最新的 C++ 版本(正式名称为标准)——C++20,因为它提供了许多方便的功能。如果由于某些原因您不能使用 C++20,我们还提供了适用于旧版本的示例。
将 lambda 与 transform 算法一起使用
要使用此算法,您必须包含algorithm
头文件。
#include <algorithm>
目标
在这个例子中,我们将创建一个数字向量,并使用 transform 算法将其中的每个数字平方。
方法
transform
算法可以传递一个函数、函数对象或 lambda。由于这是关于 lambda 的课程,我们将使用 lambda。我们的 lambda 将接受一个int
类型的参数并返回相同类型的值。
- C++20
- 直到 C++20

ranges
命名空间从 C++20 开始,我们可以使用位于ranges
命名空间中的更方便的算法版本,这就是为什么我们必须写std::ranges::transform
,而不是std::transform
。
1. 源
第一个参数是数据源——在我们的例子中是一个整数向量。
std::vector<int> data = {1, 2, 3, 4, 5};
std::ranges::transform(data, [...]);
2. 目的地
第二个参数是我们想要保存数据的容器的开头。另一个容器必须与源容器具有相同或更大的大小。我们可以使用来自data
向量的迭代器,或者来自其他一些迭代器。
std::vector<int> result;
result.resize(data.size());
std::ranges::transform(data, result.begin(), [...]);
// Also correct ✅
std::ranges::transform(data, data.begin(), [...]);
3. Lambda
算法最重要的部分,第三个参数。我们发送一个 lambda,它
- 接受一个与源容器类型相同的参数(本例中为
int
) - 返回一个与目标容器类型相同的值(本例中也为
int
)
auto square = [](int a) { return a * a; };
std::ranges::transform(data, result.begin(), square);
// We can also pass the lambda directly, without first saving it into an object:
std::ranges::transform(data, result.begin(), [](int a) { return a * a; });
4. 完整示例
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> data = {1, 2, 3, 4, 5};
std::cout << "Before using the algorithm:\n";
for(auto elem : data)
{
std::cout << elem << " ";
}
std::cout << "\n\n";
auto square = [](int a) { return a * a; };
std::ranges::transform(data, data.begin(), square);
std::cout << "After using the algorithm:\n";
for(auto elem : data)
{
std::cout << elem << " ";
}
}
Before using the algorithm:
1 2 3 4 5
After using the algorithm:
1 4 9 16 25

1. 源起点
第一个参数是数据源的开头——在我们的例子中是一个整数向量。
std::vector<int> data = {1, 2, 3, 4, 5};
std::transform(data.begin(), [...]);
2. 源结束
第二个参数是数据源的末尾。
std::transform(data.begin(), data.end(), [...]);
3. 目的地
第三个参数是我们要将数据保存到的容器的开头。另一个容器必须与源容器具有相同或更大的大小。我们可以使用来自data
向量的迭代器,或者来自其他一些迭代器。
std::vector<int> result;
result.resize(data.size());
std::transform(data.begin(), data.end(), result.begin(), [...]);
// Also correct ✅
std::transform(data.begin(), data.end(), data.begin(), [...]);
4. Lambda
算法最重要的部分,第四个参数。我们发送一个 lambda,它
- 接受一个与源容器类型相同的参数(本例中为
int
) - 返回一个与目标容器类型相同的值(本例中也为
int
)
auto square = [](int a) { return a * a; };
std::transform(data.begin(), data.end(), result.begin(), square);
// We can also pass the lambda directly, without first saving it into an object:
std::transform(data.begin(), data.end() result.begin(), [](int a) { return a * a; });
5. 完整示例
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> data = {1, 2, 3, 4, 5};
std::cout << "Before using the algorithm:\n";
for(auto elem : data)
{
std::cout << elem << " ";
}
std::cout << "\n\n";
auto square = [](int a) { return a * a; };
std::transform(data.begin(), data.end(), data.begin(), square);
std::cout << "After using the algorithm:\n";
for(auto elem : data)
{
std::cout << elem << " ";
}
}
Before using the algorithm:
1 2 3 4 5
After using the algorithm:
1 4 9 16 25
我们将在第二课中学习更多算法。