C++ 中的 Lambda 表达式 是一种轻量级的匿名函数,可以在函数内部定义并作为参数传递给算法或其他函数。它是一种便捷的方式来定义小型函数,不需要单独定义一个函数名。Lambda 表达式在 C++11 引入,并在 C++14 和 C++17 进一步扩展。
Lambda 表达式的基本语法
Lambda 表达式的一般形式为:
[捕获列表](参数列表) -> 返回类型 { 函数体 };
各部分的详细说明:
-
捕获列表(capture list):
[]
- 用于捕获 lambda 表达式外部作用域的变量,以便在 lambda 内部使用。捕获列表可以指定按值捕获、按引用捕获等方式。
- 如果不需要捕获外部变量,可以留空。
-
参数列表(parameter list):
()
- 传递给 lambda 表达式的参数,类似于函数参数列表。如果没有参数,可以省略参数名。
-
返回类型(return type):
->
- 用于指定返回类型。如果省略,编译器可以通过函数体中的
return
语句自动推断返回类型。 - 如果函数体不返回值或只有一条
return
语句,返回类型推断是可选的,通常可以省略-> 返回类型
。
- 用于指定返回类型。如果省略,编译器可以通过函数体中的
-
函数体(function body):
{}
- lambda 表达式的具体实现逻辑。
Lambda 表达式的示例
1. 基本示例:无捕获列表,无参数
#include <iostream>
int main() {
// 定义一个简单的lambda表达式
auto hello = []() {
std::cout << "Hello, World!" << std::endl;
};
// 调用lambda表达式
hello();
}
输出:
Hello, World!
2. 捕获列表示例
捕获列表用于从外部作用域捕获变量。
- 按值捕获:拷贝变量的值到 lambda 中使用。
- 按引用捕获:使用外部变量的引用,在 lambda 中修改外部变量的值。
#include <iostream>
int main() {
int x = 10;
int y = 20;
// 按值捕获x,按引用捕获y
auto lambda = [x, &y]() {
std::cout << "x: " << x << ", y: " << y << std::endl;
// x 在这里是只读的,无法修改
// y 是按引用捕获,可以修改
y = 30;
};
lambda(); // 输出: x: 10, y: 20
std::cout << "After lambda call, y: " << y << std::endl; // 输出: After lambda call, y: 30
}
输出:
x: 10, y: 20
After lambda call, y: 30
3. 参数和返回值的示例
Lambda 表达式可以接收参数和返回值,和普通函数类似。
#include <iostream>
int main() {
// 定义一个有参数并且返回值为 int 的 lambda
auto add = [](int a, int b) -> int {
return a + b;
};
int result = add(5, 10);
std::cout << "Result: " << result << std::endl; // 输出: Result: 15
}
如果 lambda 中只有一条 return
语句,且返回值可以推导,则可以省略 -> 返回类型
:
auto add = [](int a, int b) {
return a + b;
};
4. 通用捕获方式
C++ 提供一些常用的捕获方式,可以通过符号指定不同的捕获行为:
[=]
:按值捕获所有外部变量(默认捕获值)。[&]
:按引用捕获所有外部变量(默认捕获引用)。[this]
:按值捕获当前对象的this
指针,允许在 lambda 中使用类成员。[=, &var]
:按值捕获所有变量,按引用捕获var
。[&, var]
:按引用捕获所有变量,按值捕获var
。
示例:按引用捕获所有变量
#include <iostream>
int main() {
int x = 10;
int y = 20;
// 按引用捕获所有外部变量
auto lambda = [&]() {
x = 30;
y = 40;
};
lambda();
std::cout << "x: " << x << ", y: " << y << std::endl; // 输出: x: 30, y: 40
}
高级用法
1. Lambda 表达式作为参数传递
Lambda 表达式通常用作算法或函数的参数,例如 std::sort
函数:这一行代码实际上给了 sort
函数一个自定义的比较方式(lambda
表达式),用于比较对象的排序依据。
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> numbers = {3, 1, 4, 1, 5, 9};
// 使用lambda表达式按降序排序
std::sort(numbers.begin(), numbers.end(), [](int a, int b) {
return a > b;
});
for (int n : numbers) {
std::cout << n << " "; // 输出: 9 5 4 3 1 1
}
}
2. Lambda 捕获可变变量(mutable
关键字)
默认情况下,按值捕获的变量是不可修改的。如果需要在 lambda 内修改按值捕获的变量,可以使用 mutable
关键字。
#include <iostream>
int main() {
int x = 10;
// 捕获x,并在lambda内部修改x
auto lambda = [x]() mutable {
x = 20;
std::cout << "Inside lambda, x: " << x << std::endl; // 输出: Inside lambda, x: 20
};
lambda();
std::cout << "Outside lambda, x: " << x << std::endl; // 输出: Outside lambda, x: 10
}
注意:mutable
仅影响 lambda 内的拷贝,原始变量不会改变。
3. Lambda 表达式的类型
Lambda 表达式是匿名的,但它有自己的唯一类型,不能直接声明为普通函数指针。然而,可以使用 std::function
来存储 Lambda 表达式,特别是在返回类型和参数列表匹配的情况下。
#include <iostream>
#include <functional>
int main() {
std::function<int(int, int)> add = [](int a, int b) {
return a + b;
};
std::cout << "Result: " << add(3, 4) << std::endl; // 输出: Result: 7
}
总结
C++ 中的 Lambda 表达式提供了一种非常灵活、简洁的方式来定义匿名函数,广泛用于算法和函数对象。关键概念包括:
- 捕获列表用于访问外部作用域变量。
- Lambda 可以接收参数、返回值,并在必要时修改捕获变量。
- 它可以与标准库算法(如
std::sort
)配合使用,简化代码。
通过使用 Lambda 表达式,你可以编写出更具表达力和简洁性的代码,尤其是在需要传递短小功能的场景中。