C++ lambda模板

在 C++ 中,Lambda 模板 指的是能够像普通函数模板一样,接受泛型参数显式模板参数的 Lambda 表达式。

Lambda 模板的发展经历了两个阶段:

  1. C++14 的泛型 Lambda(Generic Lambdas):使用 auto 关键字实现隐式模板化。
  2. C++20 的显式模板 Lambda(Explicit Template Lambdas):引入了 `` 语法,提供了真正完整的模板能力。

一、泛型 Lambda

在 C++14 中,如果你在 Lambda 的参数列表中使用 auto,编译器会自动将其转换为一个成员模板函数

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>

int main() {
// 这是一个泛型 Lambda
auto print = [](auto x) {
std::cout << x << '\n';
};

print(10); // 实例化为 print(int)
print(3.14); // 实例化为 print(double)
print("Hello"); // 实例化为 print(const char*)
}

虽然 auto 很方便,但是也有一些问题:

  • 无法强制要求多个参数类型相同: 比如 [](auto a, auto b) 允许 aintbdouble
  • 获取参数类型极其繁琐: 如果需要知道参数的类型来定义局部变量或进行类型别名(using),就必须使用难看的 decltype[](auto x) { using T = decltype(x); ... }
  • 无法直接匹配容器模板: 如果想写一个只接受 std::vector 的 Lambda,用 auto 很难表达

二、Lambda 模板

为了解决上述局限性,C++20 引入了显式模板参数列表,语法是在 []() 之间加上 <typename T>

基本语法结构如下:

1
[] <typename T> (T a, T b) { ... }

下面以三个例子分别说明 Lambda 模板是如何解决上面提到的泛型 Lambda 所存在的问题。

  1. 强制多个参数类型相同

    1
    2
    3
    4
    5
    6
    auto addSame = []<typename T>(T a, T b) {
    return a + b;
    };

    int x = addSame(1, 2); // 正确,T 被推导为 int
    // double y = addSame(1, 2.0); // 编译错误!T 无法同时推导为 int 和 double
  2. 获取类型并进行完美转发

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // C++14 做法:必须使用 decltype 提取类型
    auto forward_c14 = [](auto&& arg) {
    doSomething(std::forward<decltype(arg)>(arg));
    };

    // C++20 做法:直接使用模板参数 T,优雅且符合常规模板习惯
    auto forward_c20 = []<typename T>(T&& arg) {
    doSomething(std::forward<T>(arg));
    };
  3. 嵌套模板匹配

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #include <vector>
    #include <iostream>

    int main() {
    // 只有当传入的是 std::vector<T> 时才匹配,并且能直接拿到元素类型 T
    auto printVector = []<typename T>(const std::vector<T>& vec) {
    // 在这里 T 就是元素的实际类型(例如 int 或 std::string)
    T sum{};
    for (const auto& elem : vec) {
    sum += elem;
    }
    std::cout << "Sum: " << sum << '\n';
    };

    std::vector<int> v{1, 2, 3};
    printVector(v); // OK

    // printVector(10); // 编译错误:10 不是 std::vector 类型
    }

三、底层原理

Lambda 本质上是一个匿名的仿函数(Functor)结构体

当你写下这个 C++20 Lambda 模板时:

1
2
3
auto myLambda = []<typename T>(T a, T b) {
return a + b;
};

C++ 编译器会在后台将其展开为类似下面的结构体:

1
2
3
4
5
6
7
8
9
10
11
// 编译器生成的匿名类
struct __UniqueLambdaName {
// 重点:operator() 被生成为了一个成员模板函数
template<typename T>
auto operator()(T a, T b) const {
return a + b;
}

// 如果有捕获组,这里还会有成员变量
};
__UniqueLambdaName myLambda{};

因为 operator() 是一个成员模板函数,所以它只有在被调用时才会被实例化(Instantiated)。


C++ lambda模板
http://example.com/2026/06/09/C++-lambda模板/
作者
Yu xin
发布于
2026年6月9日
许可协议