一、Lambda 的基础语法结构(构建的核心)

一个完整的 Lambda 表达式由 5 部分组成,其中捕获列表和函数体是必须的,其他部分可省略:

// 完整结构
[捕获列表](参数列表) mutable noexcept -> 返回类型 {
    函数体
};

// 最简结构(只有捕获列表和函数体)
[] { 函数体 };

各部分详解

部分说明是否必须
[捕获列表]定义 Lambda 能访问的外部变量(值 / 引用)✅ 必须
(参数列表)和普通函数的参数列表一致❌ 可省略(无参数时)
mutable允许修改值捕获的外部变量❌ 可省略
noexcept声明不抛出异常❌ 可省略
-> 返回类型显式指定返回类型(尾置返回类型)❌ 可省略(编译器自动推导)
{ 函数体 }函数的具体实现逻辑✅ 必须

二、核心:捕获列表的 5 种构建方式

捕获列表是 Lambda 最独特的部分,决定了 Lambda 能如何访问外部变量。

1. 空捕获 []

不捕获任何外部变量,Lambda 内部只能使用参数和全局变量。

#include <iostream>
using namespace std;

int main() {
    int a = 10;
    
    // 空捕获:不能访问 a
    auto lambda = [] { 
        // cout << a << endl; // ❌ 编译错误:未捕获 a
        cout << "Hello Lambda" << endl; 
    };
    
    lambda();
    return 0;
}

2. 值捕获 [变量名]

按值拷贝外部变量,Lambda 内部使用的是变量的副本,默认不能修改(除非加 mutable)。

#include <iostream>
using namespace std;

int main() {
    int a = 10;
    
    // 值捕获 a:内部用的是 a 的副本
    auto lambda = [a] { 
        cout << "捕获的 a: " << a << endl; 
        // a = 20; // ❌ 编译错误:值捕获默认是 const 的
    };
    
    a = 100; // 修改外部 a,不影响 Lambda 内部的副本
    lambda(); // 输出:捕获的 a: 10
    return 0;
}

3. 引用捕获 [&变量名]

按引用捕获外部变量,Lambda 内部直接修改外部变量本身。

#include <iostream>
using namespace std;

int main() {
    int a = 10;
    
    // 引用捕获 a:内部直接修改外部 a
    auto lambda = [&a] { 
        a = 20; // ✅ 可以修改外部变量
        cout << "内部修改后的 a: " << a << endl; 
    };
    
    lambda();
    cout << "外部 a: " << a << endl; // 输出:外部 a: 20
    return 0;
}

4. 隐式捕获(批量捕获)

不用逐个写变量名,让编译器自动推导需要捕获的变量:

  • [=]:所有外部变量都按值捕获;
  • [&]:所有外部变量都按引用捕获;
  • [=, &a]:大部分按值,只有 a 按引用;
  • [&, a]:大部分按引用,只有 a 按值。
#include <iostream>
using namespace std;

int main() {
    int a = 10, b = 20, c = 30;
    
    // 隐式捕获:a按值,b和c按引用
    auto lambda = [=, &b, &c] { 
        cout << "a (值): " << a << endl;
        b = 200; // 修改外部 b
        c = 300; // 修改外部 c
    };
    
    lambda();
    cout << "b: " << b << ", c: " << c << endl; // 输出:b: 200, c: 300
    return 0;
}

5. 初始化捕获(C++14 新增)

可以在捕获列表中初始化新变量,不需要依赖外部变量:

#include <iostream>
#include <memory>
using namespace std;

int main() {
    // 初始化捕获:在 Lambda 内部创建一个 unique_ptr
    auto lambda = [ptr = make_unique<int>(100)] {
        cout << "初始化捕获的 ptr: " << *ptr << endl;
    };
    
    lambda();
    return 0;
}

三、进阶:Lambda 的 3 个实用特性

1. mutable:修改值捕获的变量

值捕获的变量默认是 const 的,加 mutable 后可以修改(但修改的仍是副本,不影响外部)。

#include <iostream>
using namespace std;

int main() {
    int a = 10;
    
    // 加 mutable:可以修改值捕获的副本
    auto lambda = [a]() mutable { 
        a = 20; // ✅ 可以修改(但改的是副本)
        cout << "内部 a: " << a << endl;
    };
    
    lambda();
    cout << "外部 a: " << a << endl; // 输出:外部 a: 10(不受影响)
    return 0;
}

2. 泛型 Lambda(C++14 新增)

参数类型用 auto,让 Lambda 像模板函数一样通用:

#include <iostream>
using namespace std;

int main() {
    // 泛型 Lambda:参数类型自动推导
    auto add = [](auto x, auto y) {
        return x + y;
    };
    
    cout << add(1, 2) << endl;       // 输出:3(int)
    cout << add(1.5, 2.5) << endl;   // 输出:4.0(double)
    cout << add(string("Hello"), string(" World")) << endl; // 输出:Hello World(string)
    return 0;
}

3. Lambda 作为回调函数(最常用场景)

Lambda 最常用的场景是作为 STL 算法的回调,比如 sort、for_each:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    vector<int> nums = {3, 1, 4, 1, 5, 9};
    
    // 用 Lambda 作为 sort 的比较函数(降序排序)
    sort(nums.begin(), nums.end(), [](int a, int b) {
        return a > b;
    });
    
    // 用 Lambda 遍历输出
    for_each(nums.begin(), nums.end(), [](int num) {
        cout << num << " ";
    });
    // 输出:9 5 4 3 1 1
    return 0;
}

总结

Lambda 的构建核心是:

  1. 捕获列表:决定如何访问外部变量(值 / 引用 / 隐式 / 初始化);
  2. 参数列表:和普通函数一致,C++14 可用 auto 做泛型;
  3. 返回类型:编译器自动推导,复杂情况可显式指定;
  4. 实用场景:STL 算法回调、异步任务、快速构建匿名函数。

更多推荐