Lambda 表达式定义可在表达式位置使用的匿名函数对象,便于作为算法谓词、回调或短小的局部逻辑。编译器生成闭包类型,可捕获外围变量。本节说明捕获列表、参数与 mutable、泛型 lambda,并与STL 算法结合示例。

基本语法

C++ Lambda 与 count_if运行
#include <algorithm>
#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    int threshold = 3;
    auto count = std::count_if(v.begin(), v.end(),
        [threshold](int x) { return x > threshold; });
    std::cout << count << std::endl;
    return 0;
}

[threshold] 按值捕获;(int x) 为参数列表;函数体返回 bool。省略返回类型时由 return 推导;无 return 时返回 void。

捕获方式

捕获含义
[=]按值捕获默认所有使用到的局部变量
[&]按引用捕获,须注意生命周期不超过外围作用域
[a, &b]混合指定
[this]捕获当前对象指针,用于成员 lambda
[=, &x]默认按值,x 按引用(C++14)
int n = 0;
auto inc = [n]() mutable { return ++n; };   // 修改按值捕获的副本
std::cout << inc() << " " << n << '\n';   // 1 0

按引用捕获的变量若在 lambda 调用前已销毁,行为未定义;异步回调中尤须谨慎。

泛型 lambda(C++14)

参数写成 auto 后,同一份 lambda 可以像函数模板一样用于多种类型:twice(3) 做整数加法,twice(std::string("ab")) 做字符串拼接。C++20 也可写成 []<typename T>(T x) { ... }。

C++ 泛型 lambda运行
#include <iostream>
#include <string>

int main() {
    auto twice = [](auto x) { return x + x; };
    std::cout << twice(3) << "\n";
    std::cout << twice(2.5) << "\n";
    std::cout << twice(std::string("ab")) << "\n";
    return 0;
}

输出:

6
5
abab

与算法、线程

算法的第三个参数常常是 lambda。下面按从大到小排序,比较器用 [](int a, int b) { return a > b; }:

C++ lambda 与 sort运行
#include <algorithm>
#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {3, 1, 4, 1, 5};
    std::sort(v.begin(), v.end(), [](int a, int b) {
        return a > b;
    });
    for (int x : v) {
        std::cout << x << " ";
    }
    std::cout << "\n";
    return 0;
}

输出:

5 4 3 1 1 

lambda 也可交给 std::thread 在另一条执行流里跑。按引用捕获时,必须 join 之后变量才允许离开作用域,否则线程仍在用已经销毁的 n。异步任务见线程与互斥量、async 与 future。

C++ lambda 与 thread运行
#include <iostream>
#include <thread>

int main() {
    int n = 0;
    std::thread t([&n]() { n = 42; });  // 引用捕获,join 前 n 必须还活着
    t.join();
    std::cout << n << "\n";
    return 0;
}

输出:

42

存储与 std::function

需要类型擦除或保存不同可调用对象到同一容器时,可使用 std::function<void(int)>,有少量分配与间接调用开销;简单场景用 auto 保存 lambda 对象即可。

本节说明了 Lambda 的捕获与算法配合。下一章进入const 与 constexpr等现代 C++ 特性,并介绍并发入门。