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] 混合捕获

最佳实践 #

  1. 选择合适的捕获方式
  2. 避免悬空引用
  3. 使用auto存储Lambda
  4. 善用STL算法中的Lambda

下一步,让我们学习指针与引用!

最后更新:2026-03-26