给出代码
struct S{};
template <typename T>
auto foo(T&& t)
{
static_assert(std::is_same_v<T, std::remove_cvref_t<T>>);
}
void test()
{
const S s;
foo(s); // error
foo(S{});
S s2;
foo(s2); // error
}
T
将推导为
S const&
S
S&
为什么T
不被推导为
S const
S
S
为什么T
在左值情况下而不是右值情况下保留引用?
答案 0 :(得分:3)
转发引用的一个怪癖之一就是您永远不会只有“一个值”。
将T
推导为S
时,这仅是因为该函数实际上正在接受S&&
。
传递局部变量时,类型推导会识别出它们是左值,因此将它们绑定到常规引用。在const
的情况下为const S s
。函数签名会“更改”以反映这一点。
按照规则,您将拥有(const S&)&&
,标准表示将折叠为const S&
,然后您将拥有(S&)&&
,其折叠为仅S&
供参考折叠。
请参阅[dcl.ref]
答案 1 :(得分:2)
forwarding reference在template argument deduction中的工作方式如下:
(重点是我的)
4)如果P是对cv不合格模板参数(所谓的forwarding reference)的右值引用,并且相应的函数调用参数是左值,则使用对A的左值类型引用代替要扣除的A(注意:这是
采取行动的基础std::forward
这意味着,如果传递了左值,T
将被推导为左值引用。否则,如果在转发参考中将T
推定为左值和右值的相同类型,则无法使用std::forward
再次执行完美转发;也就是说,当传递左值时,转发为左值;传递右值时,转发为右值。