C++11 引入的 Lambda 表达式是一种匿名函数对象,它允许在代码中直接定义简短的可调用对象,无需显式定义函数或函数对象类。Lambda 表达式极大地简化了代码,尤其在处理算法、事件处理和异步编程时更为便捷。以下是对 C++ Lambda 表达式的详细介绍:
Lambda 表达式的完整语法如下:
[capture](parameters) mutable(optional) exception(optional) -> return_type { body }
[capture]
:捕获外部变量(parameters)
:与普通函数参数类似-> return_type
:自动推导时可省略(可选){ body }
:实现具体逻辑捕获子句决定了 Lambda 如何访问外部变量:
int x = 10;
auto lambda = [x] { return x * 2; }; // 捕获x的值
std::cout << lambda(); // 输出20
int x = 10;
auto lambda = [&x] { x *= 2; }; // 捕获x的引用
lambda();
std::cout << x; // 输出20
int a = 5, b = 3;
auto sum = [=] { return a + b; }; // 值捕获所有外部变量
auto product = [&] { return a * b; }; // 引用捕获所有外部变量
auto modify = [&a] { a += 10; }; // 仅引用捕获a
int x = 1, y = 2;
auto lambda = [x, &y] { return x + y++; }; // x值捕获,y引用捕获
与普通函数类似,但不能有默认参数:
auto add = [](int a, int b) { return a + b; };
std::cout << add(3, 4); // 输出7
多数情况下可省略返回类型,由编译器自动推导:
auto divide = [](double a, double b) { return a / b; }; // 返回double
如需显式指定:
auto convert = [](int x) -> double { return static_cast<double>(x); };
默认情况下,值捕获的变量不可修改。使用 mutable
可解除此限制:
int x = 10;
auto lambda = [x]() mutable { x++; return x; };
std::cout << lambda(); // 输出11
std::cout << x; // 输出10(外部x未改变)
Lambda 表达式会被编译器转换为一个匿名的函数对象(闭包类):
auto lambda = [](int x) { return x * 2; };
// 等价于(伪代码)
struct __lambda {
int operator()(int x) const { return x * 2; }
};
auto lambda = __lambda{};
std::vector<int> nums = {1, 3, 2, 5, 4};
// 排序
std::sort(nums.begin(), nums.end(), [](int a, int b) { return a < b; });
// 查找
auto it = std::find_if(nums.begin(), nums.end(), [](int x) { return x > 3; });
std::thread t([&data] {
// 在线程中处理data
process(data);
});
t.join();
button->onClick([this] {
this->updateUI();
});
使用 auto
参数创建泛型函数对象:
auto printer = [](const auto& value) {
std::cout << value << std::endl;
};
printer(42); // 输出整数
printer("Hi"); // 输出字符串
捕获时初始化新变量,可移动资源:
auto ptr = std::make_unique<int>(42);
auto lambda = [value = std::move(ptr)] { return *value; };
使用模板参数:
auto adder = []<typename T>(T a, T b) { return a + b; };
生命周期问题
引用捕获时需确保外部变量在 Lambda 执行时仍然有效。
性能考量
值捕获会复制变量,大对象建议使用引用捕获。
线程安全
多线程环境中,修改捕获的引用变量需同步。
特性 | Lambda 表达式 | 函数对象(Functor) |
---|---|---|
语法复杂度 | 简洁,内联定义 | 需定义类,实现 operator() |
状态捕获 | 自动捕获,支持值/引用 | 需手动在类中添加成员变量 |
类型安全性 | 闭包类型由编译器生成,不可见 | 类型明确,可作为模板参数 |
性能 | 通常无额外开销 | 可能有虚函数调用开销 |
以下是一个完整示例,展示 Lambda 在算法中的应用:
#include
#include
#include
int main() {
std::vector<int> nums = {1, 2, 3, 4, 5};
// 计算总和
int sum = 0;
std::for_each(nums.begin(), nums.end(), [&sum](int x) { sum += x; });
std::cout << "Sum: " << sum << std::endl; // 输出15
// 过滤偶数
std::vector<int> evens;
std::copy_if(nums.begin(), nums.end(), std::back_inserter(evens),
[](int x) { return x % 2 == 0; });
std::cout << "Evens: ";
for (int x : evens) std::cout << x << " "; // 输出2 4
return 0;
}
Lambda 表达式是 C++ 中最灵活的特性之一,合理使用可以大幅提升代码的可读性和简洁性。建议优先使用 Lambda 替代简单的函数对象,尤其是在算法调用、异步任务和事件处理中。