Lambda 表达式定义可在表达式位置使用的匿名函数对象,便于作为算法谓词、回调或短小的局部逻辑。编译器生成闭包类型,可捕获外围变量。本节说明捕获列表、参数与 mutable、泛型 lambda,并与STL 算法结合示例。
基本语法
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
int threshold = 3;
auto count = std::count_if(v.begin(), v.end(),
[threshold](int x) { return x > threshold; });
std::cout << count << std::endl;
return 0;
}[threshold] 按值捕获;(int x) 为参数列表;函数体返回 bool。省略返回类型时由 return 推导;无 return 时返回 void。
捕获方式
| 捕获 | 含义 |
|---|---|
[=] | 按值捕获默认所有使用到的局部变量 |
[&] | 按引用捕获,须注意生命周期不超过外围作用域 |
[a, &b] | 混合指定 |
[this] | 捕获当前对象指针,用于成员 lambda |
[=, &x] | 默认按值,x 按引用(C++14) |
int n = 0;
auto inc = [n]() mutable { return ++n; }; // 修改按值捕获的副本
std::cout << inc() << " " << n << '\n'; // 1 0按引用捕获的变量若在 lambda 调用前已销毁,行为未定义;异步回调中尤须谨慎。
泛型 lambda(C++14)
参数写成 auto 后,同一份 lambda 可以像函数模板一样用于多种类型:twice(3) 做整数加法,twice(std::string("ab")) 做字符串拼接。C++20 也可写成 []<typename T>(T x) { ... }。
#include <iostream>
#include <string>
int main() {
auto twice = [](auto x) { return x + x; };
std::cout << twice(3) << "\n";
std::cout << twice(2.5) << "\n";
std::cout << twice(std::string("ab")) << "\n";
return 0;
}输出:
6
5
abab与算法、线程
算法的第三个参数常常是 lambda。下面按从大到小排序,比较器用 [](int a, int b) { return a > b; }:
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {3, 1, 4, 1, 5};
std::sort(v.begin(), v.end(), [](int a, int b) {
return a > b;
});
for (int x : v) {
std::cout << x << " ";
}
std::cout << "\n";
return 0;
}输出:
5 4 3 1 1 lambda 也可交给 std::thread 在另一条执行流里跑。按引用捕获时,必须 join 之后变量才允许离开作用域,否则线程仍在用已经销毁的 n。异步任务见线程与互斥量、async 与 future。
#include <iostream>
#include <thread>
int main() {
int n = 0;
std::thread t([&n]() { n = 42; }); // 引用捕获,join 前 n 必须还活着
t.join();
std::cout << n << "\n";
return 0;
}输出:
42存储与 std::function
需要类型擦除或保存不同可调用对象到同一容器时,可使用 std::function<void(int)>,有少量分配与间接调用开销;简单场景用 auto 保存 lambda 对象即可。
本节说明了 Lambda 的捕获与算法配合。下一章进入const 与 constexpr等现代 C++ 特性,并介绍并发入门。