在 C++ 中,lambda 表达式(匿名函数)是一种便捷的函数定义方式,允许在需要函数的地方直接编写代码块,无需单独定义函数或函数对象。它是 C++11 引入的重要特性,广泛用于简化代码(尤其是配合 STL 算法)。

一、lambda 表达式的基本语法

lambda 表达式的基本格式如下:

[capture-list](parameter-list) mutable noexcept -> return-type {
    // 函数体
}

各部分含义:

  • capture-list(捕获列表):指定外部变量如何被 lambda 内部访问(如按值捕获、按引用捕获)。
  • parameter-list(参数列表):与普通函数的参数列表相同(可省略,若为空可连同()一起省略)。
  • mutable:可选,允许在 lambda 内部修改按值捕获的变量(默认不可修改)。
  • noexcept:可选,指定 lambda 不会抛出异常。
  • -> return-type(返回类型):可选,若函数体只有return语句或无返回值,可省略(编译器自动推导)。
  • 函数体:lambda 要执行的代码。

二、最简单的 lambda 示例

最简化的 lambda 可以没有参数、捕获列表和返回类型:

#include <iostream>

int main() {
    // 无参数、无捕获的lambda
    auto hello = [] {
        std::cout << "Hello, Lambda!" << std::endl;
    };
    
    hello(); // 调用lambda,输出:Hello, Lambda!
    return 0;
}

三、核心组成部分详解

1. 捕获列表(capture-list):访问外部变量

lambda 可以通过捕获列表访问定义它的作用域中的变量,主要有以下几种捕获方式:

捕获方式含义示例
[]不捕获任何外部变量-
[var]按值捕获var(复制一份,内部不可修改,除非用mutable)[x] { return x * 2; }
[&var]按引用捕获var(可修改原变量)[&x] { x++; }
[=]按值捕获所有用到的外部变量[=] { return x + y; }
[&]按引用捕获所有用到的外部变量[&] { x++; y++; }
[=, &var]除var按引用捕获外,其余按值捕获[=, &x] { x++; return y; }
[&, var]除var按值捕获外,其余按引用捕获[&, x] { y++; return x; }

示例:

#include <iostream>

int main() {
    int a = 10, b = 20;
    
    // 按值捕获a,按引用捕获b
    auto func = [a, &b] {
        // a = 30; // 错误:按值捕获的变量默认不可修改
        b = 30;   // 正确:按引用捕获的变量可修改
        return a + b;
    };
    
    std::cout << func() << std::endl; // 输出:10 + 30 = 40
    std::cout << "b = " << b << std::endl; // 输出:30(原变量被修改)
    return 0;
}

若要修改按值捕获的变量,需加mutable:

auto func = [a]() mutable {
    a = 30; // 允许修改(仅修改副本,不影响原变量)
    return a;
};
2. 参数列表与返回类型

lambda 的参数列表与普通函数一致,支持类型推导(C++14 起)、默认参数等:

// 带参数和返回类型的lambda
auto add = [](int x, int y) -> int {
    return x + y;
};
std::cout << add(2, 3) << std::endl; // 输出5

// C++14起支持参数类型自动推导(auto)
auto multiply = [](auto x, auto y) {
    return x * y;
};
std::cout << multiply(2.5, 4) << std::endl; // 输出10.0

四、lambda 的典型应用场景

1. 作为 STL 算法的回调函数

lambda 最常用的场景是配合 STL 算法(如sort、for_each),简化代码:

#include <vector>
#include <algorithm>
#include <iostream>

int main() {
    std::vector<int> nums = {3, 1, 4, 1, 5};
    
    // 用lambda作为排序的比较函数(降序)
    std::sort(nums.begin(), nums.end(), [](int a, int b) {
        return a > b; // 从大到小排序
    });
    
    // 用lambda遍历容器
    std::for_each(nums.begin(), nums.end(), [](int num) {
        std::cout << num << " "; // 输出:5 4 3 1 1
    });
    return 0;
}
2. 简化函数对象(仿函数)

在需要临时函数对象的场景(如线程、异步操作),lambda 比自定义仿函数更简洁:

#include <thread>
#include <iostream>

int main() {
    int count = 0;
    
    // 用lambda创建线程(捕获count的引用)
    std::thread t([&count]() {
        for (int i = 0; i < 1000000; ++i) {
            count++;
        }
    });
    
    t.join();
    std::cout << "count = " << count << std::endl; // 输出:1000000
    return 0;
}
3. 捕获上下文的临时逻辑

lambda 可以捕获当前作用域的变量,实现依赖上下文的临时逻辑:

#include <iostream>
#include <functional>

// 返回一个依赖于参数x的lambda
std::function<int(int)> makeAdder(int x) {
    return [x](int y) { // 捕获x
        return x + y;
    };
}

int main() {
    auto add5 = makeAdder(5);
    auto add10 = makeAdder(10);
    
    std::cout << add5(3) << std::endl;  // 输出:8
    std::cout << add10(3) << std::endl; // 输出:13
    return 0;
}

五、lambda 的本质

lambda 表达式在编译时会被转换为匿名的函数对象( functor,一种重载了operator()的类),捕获的变量会成为该类的成员变量。因此,lambda 的大小取决于捕获变量的大小(无捕获的 lambda 大小为 1,类似空类)。

例如,以下 lambda:

int x = 10;
auto func = [x](int y) { return x + y; };

编译器会生成类似这样的类:

class LambdaFunc {
private:
    int x; // 捕获的变量
public:
    LambdaFunc(int x_) : x(x_) {} // 构造函数初始化捕获的变量
    int operator()(int y) const { // 重载()运算符
        return x + y;
    }
};
auto func = LambdaFunc(x);

六、注意事项

  • 捕获列表的生命周期:按引用捕获的变量必须在 lambda 调用时仍有效,否则会导致悬空引用(如捕获局部变量后,在变量销毁后调用 lambda)。
  • mutable的影响:仅允许修改按值捕获的副本,不影响原变量。
  • 与std::function结合:lambda 可赋值给std::function(需包含<functional>),用于存储或传递匿名函数。

总结

lambda 表达式是 C++ 中简化代码的强大工具,核心优势在于:

  1. 可以在需要函数的地方直接定义,避免编写独立函数或仿函数。
  2. 灵活的捕获机制,可访问外部变量。
  3. 与 STL 算法、线程等特性无缝配合,大幅提升代码可读性和开发效率。

掌握 lambda 是编写现代 C++ 代码的必备技能,尤其在泛型编程和异步编程中应用广泛。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐