C++ Lambda表达式 #
一、Lambda概述 #
Lambda表达式是C++11引入的匿名函数,可以在需要函数的地方直接定义。
1.1 基本语法 #
cpp
[capture](parameters) -> return_type {
// 函数体
}
1.2 最简单的Lambda #
cpp
auto sayHello = []() {
std::cout << "Hello, Lambda!" << std::endl;
};
sayHello(); // 调用
1.3 带参数的Lambda #
cpp
auto add = [](int a, int b) -> int {
return a + b;
};
std::cout << add(3, 5) << std::endl; // 8
1.4 自动推导返回类型 #
cpp
// 返回类型可以自动推导
auto add = [](int a, int b) {
return a + b; // 自动推导为int
};
auto multiply = [](double a, double b) {
return a * b; // 自动推导为double
};
二、捕获列表 #
2.1 不捕获 #
cpp
int x = 10;
// 不捕获任何变量
auto func = []() {
// std::cout << x << std::endl; // 错误:无法访问x
};
func();
2.2 值捕获 #
cpp
int x = 10;
// 值捕获:复制x
auto func = [x]() {
std::cout << x << std::endl; // 10
};
x = 20;
func(); // 仍然输出10(捕获的是副本)
2.3 引用捕获 #
cpp
int x = 10;
// 引用捕获
auto func = [&x]() {
std::cout << x << std::endl; // 输出当前x的值
};
x = 20;
func(); // 输出20
2.4 隐式捕获 #
cpp
int x = 10, y = 20;
// 隐式值捕获所有使用的变量
auto func1 = [=]() {
std::cout << x << ", " << y << std::endl;
};
// 隐式引用捕获所有使用的变量
auto func2 = [&]() {
x = 30;
y = 40;
};
// 混合捕获
auto func3 = [=, &x]() { // x引用捕获,其他值捕获
x = 100; // 可以修改x
// y = 200; // 错误:y是值捕获
};
auto func4 = [&, x]() { // x值捕获,其他引用捕获
y = 200; // 可以修改y
// x = 100; // 错误:x是值捕获
};
2.5 捕获this指针 #
cpp
class MyClass {
private:
int value;
public:
MyClass(int v) : value(v) {}
void func() {
// 捕获this
auto lambda = [this]() {
std::cout << value << std::endl;
};
lambda();
// C++17:*this捕获副本
auto lambda2 = [*this]() {
std::cout << value << std::endl;
};
}
};
2.6 初始化捕获(C++14) #
cpp
int x = 10;
// 初始化捕获(移动语义)
auto func = [y = std::move(x)]() {
std::cout << y << std::endl;
};
// 初始化捕获(表达式)
auto func2 = [z = x + 5]() {
std::cout << z << std::endl; // 15
};
三、参数与返回值 #
3.1 参数 #
cpp
// 带参数
auto add = [](int a, int b) {
return a + b;
};
// 无参数
auto getPI = []() {
return 3.14159;
};
// C++14:泛型Lambda
auto addGeneric = [](auto a, auto b) {
return a + b;
};
std::cout << addGeneric(1, 2) << std::endl; // 3
std::cout << addGeneric(1.5, 2.5) << std::endl; // 4.0
3.2 返回类型 #
cpp
// 自动推导
auto func1 = []() { return 42; }; // int
// 显式指定
auto func2 = []() -> double { return 42; }; // double
// 复杂返回类型
auto func3 = []() -> std::vector<int> {
return {1, 2, 3};
};
3.3 可变Lambda #
cpp
int x = 10;
// 默认值捕获的变量是只读的
auto func1 = [x]() {
// x++; // 错误
};
// 使用mutable允许修改值捕获的变量
auto func2 = [x]() mutable {
x++; // 正确:修改的是副本
std::cout << x << std::endl;
};
func2(); // 11
func2(); // 12
std::cout << x << std::endl; // 10(原值不变)
四、实际应用 #
4.1 STL算法 #
cpp
#include <algorithm>
#include <vector>
std::vector<int> nums = {3, 1, 4, 1, 5, 9, 2, 6};
// 排序
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 > 5;
});
// 遍历
std::for_each(nums.begin(), nums.end(), [](int x) {
std::cout << x << " ";
});
// 计数
int count = std::count_if(nums.begin(), nums.end(), [](int x) {
return x % 2 == 0;
});
4.2 自定义排序 #
cpp
#include <algorithm>
#include <string>
std::vector<std::string> names = {"Alice", "Bob", "Charlie", "David"};
// 按长度排序
std::sort(names.begin(), names.end(), [](const std::string& a, const std::string& b) {
return a.length() < b.length();
});
// 按字典序排序(忽略大小写)
std::sort(names.begin(), names.end(), [](const std::string& a, const std::string& b) {
return std::lexicographical_compare(
a.begin(), a.end(),
b.begin(), b.end(),
[](char c1, char c2) { return tolower(c1) < tolower(c2); }
);
});
4.3 回调函数 #
cpp
#include <functional>
#include <vector>
// 使用std::function存储Lambda
std::function<int(int, int)> operation;
operation = [](int a, int b) { return a + b; };
std::cout << operation(3, 5) << std::endl; // 8
operation = [](int a, int b) { return a * b; };
std::cout << operation(3, 5) << std::endl; // 15
// 事件处理
std::vector<std::function<void()>> callbacks;
callbacks.push_back([]() { std::cout << "Event 1" << std::endl; });
callbacks.push_back([]() { std::cout << "Event 2" << std::endl; });
for (const auto& callback : callbacks) {
callback();
}
4.4 延迟执行 #
cpp
#include <functional>
class Deferred {
private:
std::function<void()> func;
public:
Deferred(std::function<void()> f) : func(f) {}
~Deferred() { func(); }
};
void processFile() {
FILE* file = fopen("data.txt", "r");
Deferred closeFile([file]() {
fclose(file);
std::cout << "File closed" << std::endl;
});
// 处理文件...
// 函数结束时自动关闭文件
}
4.5 线程 #
cpp
#include <thread>
#include <vector>
int main() {
std::vector<std::thread> threads;
for (int i = 0; i < 5; i++) {
threads.emplace_back([i]() {
std::cout << "Thread " << i << std::endl;
});
}
for (auto& t : threads) {
t.join();
}
return 0;
}
五、高级用法 #
5.1 立即调用 #
cpp
// 定义并立即调用
int result = [](int a, int b) {
return a + b;
}(3, 5);
std::cout << result << std::endl; // 8
5.2 递归Lambda #
cpp
#include <functional>
// 使用std::function
std::function<int(int)> factorial = [&factorial](int n) -> int {
return n <= 1 ? 1 : n * factorial(n - 1);
};
// C++14:使用auto和Y组合器
auto factorial2 = [](auto&& self, int n) -> int {
return n <= 1 ? 1 : n * self(self, n - 1);
};
int result = factorial2(factorial2, 5); // 120
5.3 模板Lambda(C++20) #
cpp
// C++20:模板Lambda
auto add = []<typename T>(T a, T b) {
return a + b;
};
std::cout << add(1, 2) << std::endl; // int
std::cout << add(1.5, 2.5) << std::endl; // double
六、捕获列表总结 #
| 捕获方式 | 语法 | 说明 |
|---|---|---|
| 不捕获 | [] |
不捕获任何变量 |
| 值捕获 | [x] |
复制x |
| 引用捕获 | [&x] |
引用x |
| 全部值捕获 | [=] |
复制所有使用的变量 |
| 全部引用捕获 | [&] |
引用所有使用的变量 |
| 混合捕获 | [=, &x] |
x引用,其他复制 |
| 混合捕获 | [&, x] |
x复制,其他引用 |
| this捕获 | [this] |
捕获this指针 |
| 初始化捕获 | [x = expr] |
C++14,表达式初始化 |
七、最佳实践 #
7.1 选择合适的捕获方式 #
cpp
// 简单读取:值捕获
int threshold = 10;
auto isGreater = [threshold](int x) {
return x > threshold;
};
// 需要修改:引用捕获
int sum = 0;
auto addToSum = [&sum](int x) {
sum += x;
};
// 大对象:引用捕获
std::vector<int> data;
auto process = [&data]() {
// 处理data
};
7.2 避免悬空引用 #
cpp
// 危险:返回引用捕获的Lambda
auto createLambda() {
int x = 10;
return [&x]() { return x; }; // x已销毁,悬空引用
}
// 正确:值捕获
auto createLambda2() {
int x = 10;
return [x]() { return x; }; // 复制x
}
7.3 使用auto存储Lambda #
cpp
// 推荐
auto func = [](int x) { return x * 2; };
// 不推荐(除非需要存储或传递)
std::function<int(int)> func2 = [](int x) { return x * 2; };
八、总结 #
Lambda语法 #
cpp
[capture](parameters) mutable -> return_type { body }
捕获方式 #
[ ]不捕获[=]值捕获所有[&]引用捕获所有[x, &y]混合捕获
最佳实践 #
- 选择合适的捕获方式
- 避免悬空引用
- 使用auto存储Lambda
- 善用STL算法中的Lambda
下一步,让我们学习指针与引用!
最后更新:2026-03-26