C++23:显式模板参数传递的递归lambda
在 C++ 中,这种语法是 C++23 引入的新特性,用于实现 显式模板参数传递的递归 lambda。下面详细解释这段代码中 this auto &dfs 的含义和作用:
1. 语法解析
auto dfs = [&](this auto &dfs, int i, int left1, int left_s) -> int {
// 函数体
};
[&]:lambda 的捕获列表,表示以引用方式捕获所有外部变量。this auto &dfs:新特性中的显式模板参数,用于传递 lambda 自身的引用,实现递归调用。auto:表示 lambda 的参数类型是泛型(模板参数)。-> int:显式指定返回类型。
2. this auto &dfs 的作用
(1) 解决 lambda 递归的经典问题
传统 lambda 无法直接递归调用自身,因为 lambda 的类型在定义时尚未完全推导。例如:
auto factorial = [](int n) -> int {
return (n <= 1) ? 1 : n * factorial(n-1); // 错误:factorial 尚未完全定义
};
此时编译器会报错,因为 factorial 在 lambda 内部尚未完成类型推导。
(2) C++23 的解决方案
通过 显式传递 lambda 自身 作为参数,绕过类型推导问题:
auto factorial = [](this auto &self, int n) -> int {
return (n <= 1) ? 1 : n * self(n-1); // 正确:通过 self 调用自身
};
this auto &self表示将 lambda 自身的引用作为第一个参数传递。- 调用时无需手动传递
self,编译器会自动处理。
3. 代码示例与对比
传统实现(需要包装为 std::function)
#include <functional>
std::function<int(int)> factorial;
factorial = [&](int n) -> int {
return (n <= 1) ? 1 : n * factorial(n-1);
};
- 需要引入
std::function和外部变量,性能较差。
C++23 新特性实现
auto factorial = [](this auto &self, int n) -> int {
return (n <= 1) ? 1 : n * self(n-1); // 直接递归调用
};
- 无需外部包装,类型安全且高效。
4. 关键点总结
| 特性 | 作用 |
|---|---|
this |
标识这是一个显式传递的模板参数(C++23 语法) |
auto &dfs |
将 lambda 自身的引用作为参数传递,类型由编译器推导 |
| 递归调用 | 通过 self(...) 或 dfs(...) 调用自身,直接支持递归 |
| 编译优化 | 相比 std::function,生成的代码更高效(类似普通函数递归) |
5. 适用场景
- 递归算法:如 DFS、分治、动态规划等。
- 需要高性能的闭包:避免
std::function的类型擦除开销。 - 模板泛型编程:结合
auto参数实现泛型递归逻辑。
6. 注意事项
- 编译器支持:需要支持 C++23 的编译器(如 GCC 13+、Clang 16+)。
- 参数顺序:
this auto &self必须作为第一个参数。 - 捕获列表:若需要修改外部变量,需确保正确捕获(示例中
[&]捕获所有引用)。
通过这种语法,C++23 使得 lambda 的递归调用更加简洁和高效,是处理递归闭包的理想选择。
好的!this auto 是 C++23 引入的 显式对象参数(Explicit Object Parameter) 语法,它允许在成员函数中显式声明 this 参数的类型。这个看似奇怪的组合其实是为了解决一些传统成员函数中的局限性。下面从语法角度详细解释:
1. 传统成员函数中的 this 指针
在 C++ 中,成员函数默认会隐式接收一个 this 指针,指向调用该函数的对象实例。例如:
struct MyClass {
int value = 42;
void print() {
std::cout << this->value; // 隐式通过 this 访问成员
}
};
- 隐式性:
this是隐式存在的,无法直接操作它的类型或传递方式。 - 局限性:无法直接表达
this的值类别(左值/右值)或推导类型,导致某些场景需要重复代码。
2. 显式对象参数 this auto 的语法
C++23 允许在成员函数中显式声明 this 参数,语法为:
struct MyClass {
void func(this auto self) { // self 是显式对象参数
// 使用 self 代替 this
}
};
语法规则
this关键字:必须作为第一个参数,且前缀为this。- 类型推导:
auto表示编译器自动推导self的类型(可能是MyClass&、const MyClass&或MyClass&&)。 - 参数名:
self是自定义名称(可任意命名,如this auto my_self)。 - 仅限成员函数:只能在非静态成员函数中使用。
3. this auto 的深层含义
(1) self 的类型推导
- 当调用
my_obj.func()时:- 若
my_obj是 左值:self推导为MyClass&。 - 若
my_obj是 右值:self推导为MyClass&&。 - 若
my_obj是 常量:self推导为const MyClass&。
- 若
- 本质上等价于传统成员函数中的
this指针,但 类型和值类别显式化。
(2) 对比传统写法
传统代码中需要手动重载不同值类别的成员函数:
struct MyClass {
void func() & { /* 左值调用 */ } // 左值重载
void func() && { /* 右值调用 */ } // 右值重载
};
使用 this auto 可以合并为一个函数:
struct MyClass {
void func(this auto self) {
// 根据 self 的值类别统一处理
}
};
4. 为什么要用 this auto?
(1) 支持递归 Lambda
传统的成员函数无法直接作为递归 Lambda,但显式对象参数可以实现:
auto factorial = [](this auto self, int n) -> int {
return (n <= 1) ? 1 : n * self(n - 1); // 递归调用 self
};
std::cout << factorial(5); // 输出 120
(2) 简化 CRTP 模式
传统 CRTP(Curiously Recurring Template Pattern)需要重复推导派生类类型:
template <typename Derived>
struct Base {
void call_derived() {
static_cast<Derived*>(this)->impl(); // 需要强制类型转换
}
};
使用 this auto 直接推导:
struct Base {
void call_derived(this auto self) {
self.impl(); // self 直接是派生类实例
}
};
(3) 统一处理值类别
避免为左值、右值、常量对象编写重复的重载函数。
5. 注意事项
- 必须用
auto:显式对象参数的类型必须由编译器推导,不能手动指定(如this MyClass& self是非法的)。 - 非静态成员函数:不能用于静态成员函数。
- 替代
this:在函数内部需要用self访问成员变量,而不是隐式的this。void func(this auto self) { self.value = 42; // 正确(假设有成员变量 value) this->value = 42; // 错误!此时 this 不存在 }
6. 示例代码对比
传统写法(C++20 及之前)
struct Widget {
void process() & { // 左值重载
std::cout << "处理左值对象\n";
}
void process() && { // 右值重载
std::cout << "处理右值对象\n";
}
};
C++23 显式对象参数
struct Widget {
void process(this auto self) {
if constexpr (std::is_lvalue_reference_v<decltype(self)>) {
std::cout << "处理左值对象\n";
} else {
std::cout << "处理右值对象\n";
}
}
};
总结
| 特性 | 显式对象参数 (this auto) |
传统成员函数 |
|---|---|---|
this 的可见性 |
显式作为参数 | 隐式存在 |
| 值类别处理 | 通过 self 自动推导 |
需手动重载 & 和 && |
| 类型推导 | 支持(如 CRTP 中直接推导派生类) | 需模板或强制类型转换 |
| 递归 Lambda | 直接支持 | 无法实现 |
this auto 是 C++23 为提升成员函数灵活性引入的重要特性,尤其适用于需要显式控制对象类型或值类别的场景。使用时需确保编译器支持 C++23 标准(如 GCC 13、Clang 17 或 MSVC 2022 17.5+)。

浙公网安备 33010602011771号