C++ 之 lambda表达式

发布于:2025-07-11 ⋅ 阅读:(15) ⋅ 点赞:(0)

在C++中,Lambda表达式(常被误写为“Lamba”)是C++11引入的核心特性,用于定义匿名函数对象(闭包),可捕获作用域内的变量并内联使用。其设计目标是简化代码、增强函数式编程能力,尤其在STL算法、异步编程和事件处理中广泛使用。以下是Lambda表达式的核心语法、特性与应用详解:

一、基础语法结构

Lambda表达式的完整语法如下:
[capture-list] (params) mutable exception -> return-type { body }

  • 捕获列表 [capture-list]:指定外部变量的捕获方式(详见下文)。
  • 参数列表 (params):与普通函数参数一致,无参时可省略括号(如 []{})。
  • 返回类型 -> return-type:可省略,编译器自动推导(复杂逻辑需显式声明)。
  • 函数体 { body }:实现具体逻辑。

二、捕获列表详解

捕获列表定义Lambda如何访问外部变量,是闭包的核心机制:

捕获方式 语法 行为
不捕获 [] 仅能使用Lambda内部定义的变量。
按值捕获 [x][=] 复制变量值到闭包,默认不可修改(需加 mutable)。
按引用捕获 [&x][&] 直接引用外部变量,修改影响原值。
混合捕获 [=, &y] y按引用捕获外,其余按值捕获。
类成员捕获 [this] 捕获当前类的this指针,可访问成员变量。
示例:
int x = 10, y = 20;
auto foo = [x, &y]() mutable { 
    x++;   // 修改副本(需mutable)
    y++;   // 修改原值
    return x + y;
};
foo();  // x=11(副本), y=21(原值)

三、关键特性与高级用法

  1. mutable关键字
    允许修改按值捕获的变量(仅影响闭包内副本,不影响原变量):

    int a = 5;
    auto lambda = [a]() mutable { a++; return a; };
    lambda();  // 返回6,但外部a仍为5 
    
  2. 返回类型推导
    单条return语句可自动推导类型;多分支或复杂逻辑需显式声明:

    auto f = [](int i) -> double { 
        if (i > 0) return i * 1.5; 
        else return i;  // 需明确类型
    };
    
  3. 泛型Lambda(C++14)
    使用auto参数支持泛型:

    auto print = [](const auto& val) { std::cout << val; };
    print(42);   // 输出整数
    print("Hi"); // 输出字符串
    
  4. 初始化捕获(C++14)
    捕获时初始化新变量,适合移动语义:

    auto ptr = std::make_unique<int>(42);
    auto lambda = [value = std::move(ptr)] { return *value; };
    

四、典型应用场景

  1. STL算法优化
    替代函数对象,提升可读性:

    std::vector<int> nums{1, 5, 3, 8};
    std::sort(nums.begin(), nums.end(), [](int a, int b) { return a > b; }); // 降序排序
    
  2. 异步编程与事件处理
    封装上下文状态,简化回调:

    std::thread t([data = std::move(data)] { 
        process(data);  // 在线程中处理数据
    }); 
    
  3. 闭包与状态保持
    Lambda可保存内部状态(类似工厂模式):

    auto makeCounter = []() {
        int count = 0;
        return [count]() mutable { return ++count; }; // 返回闭包
    };
    auto counter = makeCounter();
    counter(); // 1, counter(); // 2 
    

五、注意事项

  1. 生命周期管理

    • 按引用捕获时,需确保外部变量在Lambda执行时有效(避免悬空引用)。
    • 若Lambda被存储(如std::function),避免捕获局部变量的引用。
  2. 性能优化

    • 大对象优先按引用捕获(避免拷贝开销),但需注意线程安全。
  3. 类成员捕获
    类内Lambda需用[this][=]捕获成员变量,否则无法直接访问。

六、总结

Lambda表达式通过内联匿名函数灵活捕获机制简洁语法,极大提升了C++的现代编程体验。核心在于:

  • 优先用于短逻辑(如STL算法回调)替代传统函数对象。
  • 警惕捕获变量的生命周期,混合捕获([=, &x])平衡安全性与效率。
  • 结合C++14/20新特性(泛型、模板Lambda)可进一步强化表达能力。

七、代码

#include <iostream>
#include <vector>
#include <algorithm>
#include <memory>
#include <thread>

int main() {
    // 1. 基础Lambda:无参/带参
    auto hello = [] { std::cout << "Hello, Lambda!\n"; };  // 无参可省略()
    hello();

    auto add = [](int a, int b) { return a + b; };  // 带参Lambda
    std::cout << "3 + 5 = " << add(3, 5) << "\n\n";  // 输出: 8

    // 2. 捕获外部变量
    int x = 10, y = 20;
    // 2.1 按值捕获
    auto capture_val = [x] { 
        std::cout << "值捕获x: " << x << "\n"; 
        // x++;  // 错误:按值捕获默认不可修改(需mutable)
    };
    capture_val();

    // 2.2 按引用捕获
    auto capture_ref = [&y] { 
        y += 5;  // 修改影响外部变量
        std::cout << "引用捕获修改y: " << y << "\n";
    };
    capture_ref();
    std::cout << "外部y已变为: " << y << "\n\n";  // 输出: 25

    // 2.3 混合捕获 [=, &]
    auto mixed_capture = [=, &y] {  // x按值, y按引用
        std::cout << "混合捕获: x=" << x << " y=" << y << "\n";
    };
    mixed_capture();

    // 3. mutable关键字:允许修改值捕获的副本
    auto mutable_lambda = [x]() mutable {
        x++;  // 修改副本
        std::cout << "mutable修改副本x: " << x << "\n";
    };
    mutable_lambda();
    std::cout << "外部x未改变: " << x << "\n\n";  // 输出: 10

    // 4. STL算法结合(排序+过滤)
    std::vector<int> nums = {7, 3, 8, 1, 9, 2};
    // 4.1 Lambda作为比较器(降序排序)
    std::sort(nums.begin(), nums.end(), [](int a, int b) {
        return a > b;
    });
    std::cout << "降序排序: ";
    for (int n : nums) std::cout << n << " ";  // 输出: 9 8 7 3 2 1
    std::cout << "\n";

    // 4.2 Lambda过滤偶数
    std::vector<int> evens;
    std::copy_if(nums.begin(), nums.end(), std::back_inserter(evens),
        [](int n) { return n % 2 == 0; }  // 条件判断
    );
    std::cout << "过滤偶数: ";
    for (int e : evens) std::cout << e << " ";  // 输出: 8 2
    std::cout << "\n\n";

    // 5. 高级特性
    // 5.1 初始化捕获(C++14):移动语义捕获资源
    auto ptr = std::make_unique<int>(100);
    auto move_capture = [value = std::move(ptr)] {  // 移动捕获
        std::cout << "移动捕获值: " << *value << "\n";
    };
    move_capture();

    // 5.2 泛型Lambda(C++14):支持任意类型
    auto generic = [](auto a, auto b) { return a + b; };
    std::cout << "泛型Lambda: int=" << generic(3, 4) 
              << " double=" << generic(2.5, 3.7) << "\n";

    // 5.3 立即执行表达式(IIFE)
    const int result = [](int z) { 
        return z * z; 
    }(5);  // 定义后立即调用
    std::cout << "IIFE结果: " << result << "\n\n";  // 输出: 25

    // 6. 类成员捕获示例
    struct Widget {
        int id = 42;
        void print() {
            // 捕获this访问成员
            auto lambda = [this] { 
                std::cout << "类成员捕获: id=" << id << "\n"; 
            };
            lambda();
        }
    };
    Widget w;
    w.print();

    return 0;
}

网站公告

今日签到

点亮在社区的每一天
去签到