std::forward_like 用于将源对象的值类别和 cv 限定精准复刻到目标类型上,而非转发表达式;它接收源对象和目标类型两个参数,不依赖模板推导,只依据源对象实际表达式类别构造目标类型值。

std::forward_like 在 C++23 中不是“用来转发”的替代品,它解决的是一个更窄但真实存在的问题:在推导显式对象参数(deduced this)的成员函数中,把 this 的值类别(lvalue/rvalue)和 cv 限定符,**精准复刻到另一个类型上**。它不转发表达式,也不做完美转发;它只做“像某个对象一样地构造/转换”。
std::forward_like 是什么,和 std::forward 有什么根本区别?
std::forward 接收一个具名引用(如 T&& t),靠模板参数 T 的是否为引用折叠来决定是否转为右值;而 std::forward_like 接收两个参数:源对象(决定值类别和 cv 限定)和目标类型(决定要生成什么类型的值)。它不关心源对象的模板形参怎么推导,只看它的实际表达式类别。
-
std::forward:依赖(x) T是否是U&或U&&来决定是否static_cast(x) -
std::forward_like(x):不管x是怎么声明的,只看x当前是 lvalue 还是 prvalue,再结合U的 cv 限定,生成对应类别的U值 —— 比如std::forward_like得到(42) const int&&,std::forward_like((i) i是int&)得到int&
为什么推导 this 的成员函数里特别需要 forward_like?
当使用 auto& self 或 MyClass& self 作为显式对象参数时,self 的类型是确定的(比如 MyClass& 或 const MyClass&&),但它不能直接用于构造另一个类型(如 Wrapper)并保持原 this 的 cv 和值类别。手动写 static_cast 容易出错,尤其在重载集里。
- 错误写法:
Wrapper{self}→ 总是调用Wrapper(const MyClass&),丢失self是 rvalue 的信息 - 正确写法:
Wrapper{std::forward_like→ 若(self)} self是MyClass&&,则传入Wrapper&&;若self是const MyClass&,则传入const Wrapper& - 典型场景:实现
operator()、to_string()、as_view()等需保持调用者语义的代理方法
forward_like 的典型误用和兼容性注意点
它不是万能的“转发工具”,滥用反而破坏语义。C++23 标准库目前仅在少数地方(如 std::ranges::ref_view 的构造)用到它,且要求目标类型必须可由源对象隐式转换或显式构造。
立即学习“C++免费学习笔记(深入)”;
- 不能用于非可构造类型:
std::forward_like编译失败(x) - 不处理引用坍缩:
std::forward_like不等于(x) std::move(x),它仍按x实际值类别 +int&&的 cv 限定合成结果(可能为int&) - Clang 16+ / GCC 13+ 支持,MSVC 19.35+ 开始实验性支持;旧编译器需自行实现(基于
decltype+static_cast+std::is_lvalue_reference_v) - 别把它和
std::move或std::forward混用:比如std::forward_like是冗余的,因为(std::move(x)) std::move(x)已经是 prvalue,forward_like只会再套一层T&&
真正容易被忽略的是:它不改变源对象本身,也不触发移动语义 —— 它只是“描述如何从 A 构造 B”。如果你需要转移资源,该用 std::move;如果你要泛型转发参数,还是用 std::forward;只有当你明确要“让新对象拥有和 this 一样的 cv + 值类别投影到另一类型上”,才轮到 std::forward_like 出场。










