💡 一分钟速览:C++20 Lambda 表达式(上):模板语法与类型约束详解,外加 C++23 deducing this 如何让递归 lambda 变成一行代码,不再依赖 std::function。
最后更新:2026-10-13
C++20 Lambda 表达式(上)¶
C++20之lambda模版¶
C++14 支持泛型 lambda 表达式,这使得 lambda 可以接受任意类型的参数,例如:
会被展开为:
struct Func {
template <typename T1, typename T2>
auto operator()(T1 a, T2 b) const {
return a + b;
}
};
但是却无法做到下面几种展开式:
第一种:相同类型
第二种:只有std::array
第三种:没有推导
C++14 lambdas 很好,但是 C++20 允许我们轻松实现这些情况。C++20允许lambda表达式在定义中使用模版类型参数,以下是基本的语法:
下面通过几个示例说明它的好处。
1.类型限定¶
像下面这种例子,C++14我们可以写出下面的代码,但是我们在使用的时候传递进来的不一定是一个vector,那么与预期的行为就会不一致,从而产生错误。
C++20之后,我们可以限定其类型:
那么问题来了,出一个面试题目:你知道C++14中为了限定vector,怎么才能保证安全呢?
2.完美转发¶
在C++20中你可以非常轻松的使用完美转发,例如:
那么问题来了,相比于C++14来说,有什么优势?或者说C++14实现完美转发需要做什么?
本节完
递归 Lambda:deducing this 一次讲清(C++23)¶
普通 lambda 没法喊出自己的名字,所以递归以前只有两条路:把 lambda 存进 std::function(有分配、有间接调用),或者套一层 Y 组合子(聪明,但没法读)。C++23 的显式对象形参——就是 deducing this 那个特性——优雅地解决了这件事:lambda 把自己当作第一个参数收进来:
// C++23 explicit object parameter: the lambda receives itself
auto factorial = [](this auto self, int n) -> long long {
return n <= 1 ? 1 : n * self(n - 1);
};
static_assert(factorial(10) == 3628800);
// before C++23 you needed std::function (heavy) or a Y-combinator (clever)
self 参数在每次调用时推导,所以泛型递归也没问题:同一个 lambda 能在任意类型上递归,两个 lambda 互相传递自身还能玩互递归。因为编译器能看穿 self,这些调用的内联效果跟你手写具名函数一样。
编译器支持:GCC 14+、Clang 18+、MSVC 自 VS 2022 17.2 起,编译加 -std=c++23。
常见问题¶
C++ 里怎么写递归 lambda?¶
C++23 起给 lambda 加显式对象形参:[](this auto self, int n) { ... self(n-1) ... }。更早的版本只能用 std::function、Y 组合子,或者干脆写具名函数。
deducing this 写的递归 lambda 和普通函数一样快吗?¶
实践中一样:编译器会对 self 做特化并内联,不像 C++23 之前 std::function 那条路必须走间接调用。
deducing this 能配合泛型 lambda 吗?¶
能。self 每次调用按 auto&& 推导,同一个 lambda 可以在不同类型上递归,两个 lambda 互相传递自身还能实现互递归。
相关主题¶
- C++20 协程入门 | C++那些事
- C++20 channel 实战 | C++那些事
- C++20 Concepts 概念 | C++那些事
- C++20 constexpr 与逗号表达式 | C++那些事
- C++20 字节序 endian | C++那些事
- C++20 模块 Modules | C++那些事
- C++20 Ranges 库 | C++那些事
- C++20 std::span 设计与陷阱 | C++那些事
- C++20 新特性导读 | C++那些事
- C++20 [[likely]] 与 [[unlikely]] | C++那些事