【C++】 Lambda 表达式详解

Lambda 表达式是 C++11 引入的匿名函数对象,用于简化代码、支持函数式编程风格,并替代传统函数对象(如仿函数)。其核心功能是在作用域内捕获变量,并定义轻量级的局部函数逻辑


一、Lambda 表达式的基本语法

语法结构
[捕获列表] (参数列表) -> 返回类型 {
    函数体
}
  • 捕获列表(Capture List)​:指定如何从外部作用域捕获变量。
  • 参数列表(Parameter List)​:与普通函数的参数列表一致。
  • 返回类型(Return Type)​:可省略(编译器自动推导),复杂时需显式声明。
  • 函数体(Body)​:执行逻辑。
示例
auto lambda = [](int a, int b) -> int {
    return a + b;
};
int result = lambda(3, 4);  // result = 7

二、捕获列表(Capture List)​

1. 捕获方式
语法 行为
[] 不捕获任何外部变量。
[=] 按值捕获所有外部变量(隐式捕获)。
[&] 按引用捕获所有外部变量(隐式捕获)。
[x, &y] 显式按值捕获 x,按引用捕获 y(混合捕获)。
[this] 捕获当前类的 this 指针,可访问成员变量和函数。
[*this] (C++17) 按值捕获当前对象的副本(避免悬垂引用)。
2. 示例
int x = 10;
int y = 20;

// 按值捕获 x,按引用捕获 y
auto lambda = [x, &y]() {
    y = x + y;  // x 是副本,y 是引用
};
lambda();
// x=10(未变),y=30
3. 初始化捕获(C++14)​

允许在捕获列表中初始化变量(类似闭包):

auto x = 5;
auto lambda = [y = x + 1] { return y; };  // y 初始化为 6

三、mutable 关键字

  • 功能:允许在 Lambda 体内修改按值捕获的变量(默认按值捕获的变量是 const)。
  • 示例
    int x = 0;
    auto lambda = [x]() mutable {
        x++;  // 允许修改 x 的副本
        return x;
    };
    lambda();  // 返回 1,但外部 x 仍为 0

四、返回类型推导

  • 隐式推导:若函数体仅有一个 return 语句,编译器自动推导返回类型。
  • 显式声明:复杂逻辑需显式指定返回类型:
    auto lambda = [](int a, double b) -> double {
        if (a > 0) return a + b;
        else return b;
    };

五、泛型 Lambda(C++14)​

  • 功能:参数支持 auto,使 Lambda 可接受任意类型参数。
  • 示例
    auto print = [](const auto& value) {
        std::cout << value << "\n";
    };
    print(42);        // int
    print("Hello");   // const char*

六、应用场景

1. STL 算法中的回调函数
std::vector<int> vec = {3, 1, 4, 1, 5};
std::sort(vec.begin(), vec.end(), [](int a, int b) {
    return a > b;  // 降序排序
});
2. 异步任务封装
#include <thread>
#include <future>

auto task = [](int x) {
    return x * x;
};
std::future<int> result = std::async(std::launch::async, task, 5);
3. 事件处理(如 GUI 回调)​
button.onClick([&]() {
    updateUI();  // 捕获外部引用,访问 UI 组件
});

七、C++17/20 增强

1. constexpr Lambda(C++17)​

Lambda 可在编译时求值:

constexpr auto square = [](int x) { return x * x; };
static_assert(square(5) == 25, "");
2. 模板参数列表(C++20)​

支持显式模板参数:

auto lambda = []<typename T>(T x) { return x; };

八、注意事项

  1. 悬空引用
    避免捕获局部变量的引用后,其生命周期结束(如异步任务中)。

  2. this 指针捕获:
    若对象已销毁,通过 [this] 或 [&] 访问成员会导致未定义行为。

  3. 性能影响
    Lambda 会生成匿名类对象,频繁捕获大对象可能影响性能。


九、总结

特性 说明
捕获列表 按值/引用捕获变量,支持混合捕获和初始化捕获(C++14)。
mutable 允许修改按值捕获的变量副本。
泛型 Lambda(C++14) 参数支持 auto,处理多类型。
constexpr(C++17) 编译时求值。
应用场景 STL 算法、异步任务、事件处理。

Lambda 表达式通过简洁的语法替代传统函数对象,极大提升了代码可读性和灵活性,是现代 C++ 开发的核心工具之一。