c++lambda表达式
前言:关于c++中lambda表达式很久之前就想写一个教程了
C++ Lambda 表达式教程
1. 什么是 Lambda 表达式?
Lambda 表达式是 C++11 引入的一种匿名函数对象,允许你在需要函数的地方直接定义内联函数,无需显式命名。它们常用于:
- 作为算法(如
std::sort
、std::for_each
)的参数 - 实现回调函数
- 简化代码逻辑
2. 基本语法
Lambda 表达式的基本结构:
[capture list](parameter list) -> return type { function body }
- 捕获列表
[]
:定义如何捕获外部变量(如[x, &y]
) - 参数列表
()
:类似普通函数的参数(可省略,如[]{};
) - 返回类型
-> type
:可省略(编译器自动推导) - 函数体
{}
:函数的具体实现
示例 1:最简单的 Lambda
[]() { std::cout << "Hello, Lambda!"; }(); // 直接调用
// 输出:Hello, Lambda!
示例 2:带参数和返回值
auto add = [](int a, int b) -> int { return a + b; };
std::cout << add(3, 4); // 输出:7
3. 捕获列表详解
捕获列表决定了 lambda 如何访问外部变量:
捕获方式 | 语法 | 说明 |
---|---|---|
无捕获 | [] | 不捕获任何外部变量,函数体内不能使用外部变量 |
值捕获 | [x, y] | 按值捕获变量 x 和 y (复制一份到 lambda 内部) |
引用捕获 | [&x, &y] | 按引用捕获变量 x 和 y (直接访问外部变量) |
混合捕获 | [x, &y] | 值捕获 x ,引用捕获 y |
隐式值捕获 | [=] | 按值捕获所有外部变量 |
隐式引用捕获 | [&] | 按引用捕获所有外部变量 |
混合隐式捕获 | [=, &x] | 按值捕获所有变量,但 x 按引用捕获 |
示例 3:值捕获与引用捕获
int x = 10;
auto value_capture = [x]() { return x + 1; }; // 值捕获
auto ref_capture = [&x]() { return x + 1; }; // 引用捕获x = 20;
std::cout << value_capture(); // 输出:11(捕获的是 x 的副本)
std::cout << ref_capture(); // 输出:21(捕获的是 x 的引用)
4. 递归 Lambda
若需要在 lambda 内部递归调用自身,需使用 std::function
显式声明类型:
示例 4:递归计算阶乘
#include <functional>std::function<int(int)> factorial = [&factorial](int n) {return (n <= 1) ? 1 : n * factorial(n - 1);
};std::cout << factorial(5); // 输出:120
5. Lambda 在标准库中的应用
Lambda 常用于标准库算法中,替代传统的函数对象。
示例 5:使用 Lambda 排序
#include <algorithm>
#include <vector>std::vector<int> nums = {3, 1, 4, 1, 5};
std::sort(nums.begin(), nums.end(), [](int a, int b) { return a > b; }); // 降序排序// 输出:5 4 3 1 1
for (int num : nums) std::cout << num << " ";
示例 6:使用 Lambda 过滤元素
#include <algorithm>
#include <vector>std::vector<int> nums = {1, 2, 3, 4, 5};
auto even_count = std::count_if(nums.begin(), nums.end(),[](int x) { return x % 2 == 0; });std::cout << "偶数数量:" << even_count; // 输出:2
6. 可变 Lambda
默认情况下,值捕获的变量在 lambda 内部是只读的。若需要修改,需使用 mutable
关键字:
示例 7:可变 Lambda
int x = 10;
auto increment = [x]() mutable { x++; return x; };std::cout << increment(); // 输出:11
std::cout << x; // 输出:10(外部 x 未被修改)
7. 泛型 Lambda(C++14+)
C++14 允许使用 auto
参数创建泛型 lambda:
示例 8:泛型 Lambda
auto add = [](auto a, auto b) { return a + b; };std::cout << add(3, 4); // 输出:7(int + int)
std::cout << add(3.1, 4.2); // 输出:7.3(double + double)
8. Lambda 与移动语义
C++14 允许使用初始化捕获(也称为广义捕获),支持移动语义:
示例 9:移动捕获
#include <memory>auto ptr = std::make_unique<int>(42);
auto lambda = [value = std::move(ptr)]() { return *value; };std::cout << lambda(); // 输出:42
9. 注意事项
- 生命周期问题:引用捕获时需确保引用的变量在 lambda 执行时仍然有效。
- 性能考虑:值捕获会复制变量,大型对象建议使用引用捕获。
- 可调用对象类型:普通 lambda 的类型是唯一的,不可直接比较;
std::function
可存储任意可调用对象,但有额外开销。
10. 总结
Lambda 表达式使 C++ 代码更简洁、灵活,尤其在处理算法、回调等场景时优势明显。掌握 lambda 的关键在于理解捕获列表和参数传递方式,根据场景选择合适的捕获策略。