💡 一分钟速览:通过已编译验证的递归 lambda 与成员函数示例解释 C++23 deducing this、const 和值类别转发,以及编译器要求和常见陷阱。
最后更新:2026-10-31
C++23 deducing this:显式对象参数¶
*显式对象参数*让成员函数或 lambda 给调用它的对象命名。常说的“deducing this”通常指该参数类型由编译器推导的写法。这是 WG21 P0847R7 引入的 C++23 语言特性,不属于 C++20 lambda。
当一个操作要覆盖 const 和不同值类别,或递归 lambda 需要调用自身时,它很有用。普通成员函数若没有这些需求,传统的隐式 this 更容易读懂。
不用 std::function 写递归 lambda¶
#include <cassert>
int main() {
auto factorial = [](this auto const& self, int n) -> int {
return n <= 1 ? 1 : n * self(n - 1);
};
assert(factorial(5) == 120);
}
第一个参数指向 lambda 对象,self(n - 1) 再次调用它。调用方仍写 factorial(5),不必把 lambda 自身显式传进去,也无需 std::function 类型擦除包装。这并不能证明所有递归 lambda 都更快;性能敏感时应检查生成代码并测试真实负载。
一个成员函数保留 const 与值类别¶
#include <string>
#include <type_traits>
#include <utility>
struct Buffer {
std::string text;
template<class Self>
decltype(auto) get(this Self&& self) {
return (std::forward<Self>(self).text);
}
};
static_assert(std::is_same_v<decltype(std::declval<Buffer&>().get()), std::string&>);
static_assert(std::is_same_v<decltype(std::declval<const Buffer&>().get()), const std::string&>);
static_assert(std::is_same_v<decltype(std::declval<Buffer&&>().get()), std::string&&>);
int main() {
Buffer b{"hello"};
return b.get() == "hello" ? 0 : 1;
}
Self&& 根据调用方推导;std::forward<Self>(self) 保留 const 与左值/右值类别。return (expression); 的括号不能随意去掉:配合 decltype(auto),括号保留表达式的引用类型;去掉后,这种成员访问可能推导出成员的声明类型并返回副本。不要在临时 Buffer 已销毁后继续保存从它取得的引用。
编译器与设计边界¶
使用 Clang 18 或更新版本,以 clang++ -std=c++23 -Wall -Wextra -pedantic example.cpp 编译。本文两个示例已在 Compiler Explorer 的 Clang 20.1.0 中编译并运行。本站本地的 Apple Clang 16 尚不支持该特性,仅加 -std=c++23 不够;复制代码前请查看 Clang 实现状态或所用编译器的支持情况。
显式对象成员函数内部用命名参数 self,不能依赖隐式 this。若按值传对象会产生复制;按所有权与修改需求选择 Self&&、const Self& 或具体引用类型。显式对象成员函数不能是 virtual。
接着读 const 全家桶了解修饰符和转发,再读 C++20 lambda了解 C++23 以前的背景。这两篇只含简短示例,本文集中解释功能的设计与边界。