Logo成贤计协指南

匿名函数

认识 Lambda

有些时候,我们可能会需要把函数作为参数进行传递:

int func(std::function<int(int, int)> fn) {
    return fn(1, 2);
}

int i_will_pass_this_func(int a, int b) { /* */ }
int i_will_pass_this_func2(int a, int b) { /* */ }

int main() {
    func(i_will_pass_this_func);
    func(i_will_pass_this_func2);

    return 0;
}

很显然,在这种情况下,为了传递一个参数而专门定义一个甚至多个完整的函数,显得冗余且复杂。同时,我们还无法灵活地动态改变函数内部的逻辑。

这时候,匿名函数的作用就体现出来了。

Lambda 表达式的定义和使用

C++11 引入了 Lambda 表达式(匿名函数)。Lambda 表达式允许我们在需要的地方直接定义一个匿名函数,并且可以捕获外部变量,使得函数逻辑更加灵活。

Lambda 表达式的基本语法如下:

[捕获列表](参数列表) -> 返回类型 {
    // 函数体
}
int func(std::function<int(int, int)> f) {
    return f(1, 2);
}

int main() {
    func([](int a, int b) -> int {
        return a + b;
    });

    // 如果不写返回类型,编译器也会自动推断返回类型
    func([](int a, int b) {
        return a * b;
    });

    return 0;
}

捕获外部变量

Lambda 表达式的强大之处在于它可以捕获外部变量。例如:

int x = 10, y = 20;
auto add_x = [x, y](int a) {
    return a + x + y;
}; // 你也可以把匿名函数赋值给变量,这个变量就可以当函数来使用
std::cout << add_x(5);

捕获列表可以指定要捕获哪些变量,以及捕获方式(值捕获或引用捕获)。

  • [x]:以值捕获变量 x
  • [&x]:以引用捕获变量 x
  • [=]:以值捕获所有外部变量
  • [&]:以引用捕获所有外部变量

应用:Lambda 与标准库算法结合

许多标准库算法都用到了 Lambda 表达式,例如 std::sortstd::for_each

main.cpp
// 想要运行下面的代码,请确保你的项目为 C++23 及以上版本的标准
#include <algorithm> // sort 需要引入这个头文件
#include <print>

int main() {
    int arr[] = {4, 2, 1, 3, 5};

    std::sort(arr, arr + 5, [](int a, int b) {
        return a > b; // 降序排序,a < b 就是升序排序
    });

    std::for_each(arr, arr+5, [](int n) {
        std::println(n);
    }); // 遍历整个 arr 并输出所有项。在这里可以使用 for range 来代替

    return 0;
}