c++左值右值,万能引用以及完美转发

引用折叠规则

引用折叠是 C++ 中处理引用类型推导的规则。具体规则如下:

  • T& & 变为 T&
  • T& && 变为 T&
  • T&& & 变为 T&
  • T&& && 变为 T&&

1.万能引用:

我们知道左值和右值引用,其中右值引用应用于实现移动构造和复制构造,比如:
MyClass(MyClass&& other),MyClass& operator=(MyClass&& other)

万能引用就是既可以传左值,又可以传右值,万能引用的前提:必须是函数模板,也就是说,在右值引用的前提下加上函数模板,就升级成了万能引用。

  • 当传递左值(如 x)时

    • T 会被推导为 int&,因此 T&& 实际上变为 int& &&,这是一个右值引用类型。
    • 结果是 arg 变为 int&(左值引用),所以 typeid(arg).name() 打印的结果是 i,表示 int&
  • 当传递右值(如 20)时

    • T 会被推导为 int,因此 T&& 实际上变为 int&&,这是一个右值引用类型。
    • 结果是 arg 变为 int(右值),所以 typeid(arg).name() 打印的结果是 i,表示 int

如果要区分两个i,可以用is_lvalue_reference<T>::value,如果是左值,会返回true

2.完美转发

  • std::forward 是实现完美转发的关键工具。它根据传递给它的模板参数的值类别来决定如何转发参数。
  • 如果 T 是左值引用,则 std::forward<T>(arg)arg 转发为左值引用;如果 T 是右值引用,则 std::forward<T>(arg)arg 转发为右值引用。

为什么要用完美转发:

使用完美转发vs不使用完美转发

(1)使用:

  • myForward(x) 调用

    • T 被推导为 int&,因此 std::forward<T>(arg)arg 以左值的形式传递给 process
    • process 函数中的 T&& 被折叠为 int&,保留了 x 的左值特性。
  • myForward(20) 调用

    • T 被推导为 int,因此 std::forward<T>(arg)arg 以右值(T&&)的形式传递给 process
    • process 函数中的 T&& 被折叠为 int&&,保留了 20 的右值特性。

(2)不使用

        

  • myForward(x) 调用

    • T 被推导为 int&,因此 T&& 变为 int& &&int& && 实际上是 int&,因为左值引用不能绑定到右值引用上。
    • 传递到 processarg 类型是 int&,即使 arg 是左值,process 函数中的 arg 类型也是 int&,这意味着在 process 中处理的是 x 的左值特性。
  • myForward(20) 调用

    • T 被推导为 int,因此 T&& 变为 int&&
    • 传递到 processarg 类型是 int,即使 arg 是右值,process 函数中的 arg 类型也是 int,这丢失了右值的特性,被当做普通的值进行处理。

不使用完美转发的影响:

  • 丢失右值特性

    • T 是左值引用时,T&& 的折叠结果是左值引用(int&)。如果传递的是右值(如 20),在 process 函数中,arg 的类型仍然是 int,丢失了右值特性。这样,可能会导致右值被当作左值处理,从而可能影响性能(如不必要的拷贝)。
  • 可能不必要的拷贝或移动

    • 如果在 process 函数中,你希望进行移动操作(例如使用 std::move),但由于没有使用 std::forward,右值传递可能被当作左值处理,导致拷贝操作而非移动操作,这会影响效率。

  • 18
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值