折叠转发参考

时间:2020-02-22 15:35:59

标签: c++ c++20

给出代码

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将推导为

  1. S const&
  2. S
  3. S&

为什么T不被推导为

  1. S const
  2. S
  3. S

为什么T在左值情况下而不是右值情况下保留引用?

playground

2 个答案:

答案 0 :(得分:3)

转发引用的一个怪癖之一就是您永远不会只有“一个值”。

T推导为S时,这仅是因为该函数实际上正在接受S&&

传递局部变量时,类型推导会识别出它们是左值,因此将它们绑定到常规引用。在const的情况下为const S s。函数签名会“更改”以反映这一点。

按照规则,您将拥有(const S&)&&,标准表示将折叠为const S&,然后您将拥有(S&)&&,其折叠为仅S&供参考折叠。

请参阅[dcl.ref]

See for yourself(实时演示)

答案 1 :(得分:2)

forwarding referencetemplate argument deduction中的工作方式如下:

(重点是我的)

4)如果P是对cv不合格模板参数(所谓的forwarding reference)的右值引用,并且相应的函数调用参数是左值,则使用对A的左值类型引用代替要扣除的A(注意:这是std::forward

采取行动的基础

这意味着,如果传递了左值,T将被推导为左值引用。否则,如果在转发参考中将T推定为左值和右值的相同类型,则无法使用std::forward再次执行完美转发;也就是说,当传递左值时,转发为左值;传递右值时,转发为右值。

相关问题