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 的构造)用到它,且要求目标类型必须可由源对象隐式转换或显式构造。