C++11引入了Lambda表达式,它是一种在函数内部定义匿名函数的方式。Lambda表达式使得代码更加简洁和灵活,特别是在需要短小的函数对象时。
基本语法
Lambda表达式的基本语法如下:
[capture](parameters) -> return_type {
// function body
}
capture
:捕获列表,指定 Lambda 表达式可以访问外部变量的方式。parameters
:函数参数列表,类似于普通函数的参数。return_type
:返回类型,通常可以省略,编译器会自动推导。function body
:Lambda 表达式的主体,包含实际的代码。
示例
-
简单的 Lambda 表达式:
auto add = [](int a, int b) { return a + b; }; std::cout << add(3, 4); // 输出 7
-
带捕获列表的 Lambda 表达式:
int x = 10; auto printX = [x]() { std::cout << x << std::endl; }; printX(); // 输出 10
在这个例子中,
[x]
表示捕获外部变量x
的值。x
是按值捕获的。 -
捕获外部变量的引用:
int x = 10; auto incrementX = [&x]() { x++; }; incrementX(); std::cout << x; // 输出 11
这里
&x
表示捕获外部变量x
的引用,因此在 Lambda 表达式内对x
的修改会影响到外部的x
。 -
捕获所有变量(值捕获和引用捕获):
int x = 10, y = 20; auto printXY = [=]() { // 捕获所有外部变量的值 std::cout << x << " " << y << std::endl; }; printXY(); // 输出 10 20 auto modifyXY = [&]() { // 捕获所有外部变量的引用 x = 30; y = 40; }; modifyXY(); std::cout << x << " " << y << std::endl; // 输出 30 40
[=]
表示按值捕获所有外部变量,[&]
表示按引用捕获所有外部变量。 -
指定返回类型:
auto divide = [](double a, double b) -> double { if (b == 0) throw std::runtime_error("Division by zero"); return a / b; }; std::cout << divide(10, 2); // 输出 5
在这个例子中,
-> double
明确指定了返回类型为double
。 -
在 STL 算法中使用 Lambda 表达式:
std::vector<int> numbers = {1, 2, 3, 4, 5}; std::for_each(numbers.begin(), numbers.end(), [](int n) { std::cout << n << " "; }); // 输出 1 2 3 4 5
在 STL 算法中,Lambda 表达式通常用于简化回调函数的定义。
注意事项
- 捕获列表的多样性: 捕获列表可以为空(
[]
),或者只包含特定变量([x]
),或者所有变量的值([=]
),或者所有变量的引用([&]
),也可以混合使用([=, &x]
)。 - Lambda 表达式的类型: Lambda 表达式的类型是由编译器生成的一个特殊的函数对象类型,通常是匿名的。
Lambda 表达式提供了一种在函数内部定义并使用局部函数的方式,使代码更加灵活和易于阅读。
使用场景
Lambda 表达式在 C++ 中提供了一种简洁且强大的方法来创建匿名函数对象。它们适用于各种场景,包括回调函数、算法操作、事件处理等。下面是一些常见的使用场景和具体用法示例:
1. STL 算法中的回调
Lambda 表达式经常用于 STL 算法中的回调函数,例如 std::sort
、std::for_each
、std::find_if
等。
#include <algorithm>
#include <vector>
#include <iostream>
int main() {
std::vector<int> numbers = {5, 2, 9, 1, 5, 6};
// 使用 Lambda 表达式对向量进行排序
std::sort(numbers.begin(), numbers.end(), [](int a, int b) {
return a < b;
});
// 打印排序后的向量
std::for_each(numbers.begin(), numbers.end(), [](int n) {
std::cout << n << " ";
});
return 0;
}
2. 事件处理
Lambda 表达式可以用于事件处理,特别是在 GUI 编程中,例如使用 Qt 或其他事件驱动框架。
#include <QPushButton>
#include <QApplication>
#include <QMessageBox>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QPushButton button("Click me");
QObject::connect(&button, &QPushButton::clicked, [&]() {
QMessageBox::information(nullptr, "Message", "Button clicked!");
});
button.show();
return app.exec();
}
3. 自定义比较函数
在需要自定义比较逻辑的地方,Lambda 表达式可以简化代码。
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> numbers = {10, 20, 30, 40, 50};
// 使用 Lambda 表达式找到第一个大于 25 的元素
auto it = std::find_if(numbers.begin(), numbers.end(), [](int n) {
return n > 25;
});
if (it != numbers.end()) {
std::cout << "First number greater than 25 is: " << *it << std::endl;
}
return 0;
}
4. 简化回调函数
Lambda 表达式可以替代传统的函数对象或函数指针,简化回调函数的定义。
#include <iostream>
#include <functional>
void process(std::function<void()> callback) {
// 执行回调
callback();
}
int main() {
// 使用 Lambda 表达式作为回调函数
process([]() {
std::cout << "Callback executed!" << std::endl;
});
return 0;
}
5. 生成函数对象
在需要生成函数对象时,Lambda 表达式可以使代码更简洁。
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5};
// 使用 Lambda 表达式生成平方函数对象
std::transform(numbers.begin(), numbers.end(), numbers.begin(), [](int n) {
return n * n;
});
// 打印结果
for (int n : numbers) {
std::cout << n << " ";
}
return 0;
}
6. 捕获外部变量
Lambda 表达式能够捕获外部变量,使得在闭包中可以访问这些变量。
#include <iostream>
int main() {
int x = 10;
auto lambda = [x]() mutable { // `mutable` 允许修改捕获的 `x`
std::cout << "Captured x: " << x << std::endl;
x += 5;
std::cout << "Modified x: " << x << std::endl;
};
lambda();
std::cout << "Outside x: " << x << std::endl; // 输出 10
return 0;
}
7. 延迟执行
Lambda 表达式可以延迟执行,适用于生成惰性计算的代码。
#include <iostream>
#include <functional>
int main() {
int a = 5, b = 10;
// 延迟计算
auto delayedSum = [a, b]() {
return a + b;
};
std::cout << "Delayed sum: " << delayedSum() << std::endl;
return 0;
}
总结
Lambda 表达式在 C++ 中提供了一种方便的方式来定义临时的匿名函数对象。它们在需要简洁、局部的函数逻辑时非常有用,尤其是在 STL 算法、事件处理、回调函数、自定义比较、生成函数对象等场景中。使用 Lambda 表达式可以使代码更加清晰、可维护。