《Effective Modern C++》条款28:理解引用折叠

本章节主要说一下引用折叠的问题,解释一下型别推导形参的问题;

Pre:

先注意以下几点:

  1. 右值的引用自己本身是左值;
  2. 先进行型别推导,推导之后产生T,之后在引用冲突的地方进行引用折叠;
  3. 引用折叠只出现在:型别推导,auto推导,dectype推导,typedef推导这四个地方,其他不会进行引用推导;

基本概念:

对于常规双引用,会直接报错,原因是:

C++中不允许双引用,也就是说,不允许产生引用的引用,例如: int& &a这种情况

但是引用折叠确实引用的引用;

之前说过,例如:

class widget {};

template<typename T> void func(T&& param);

其中T&&是万能引用,和之前所以提到的,T会根据param来进行推导,的到T的类型;

根据前三个条款中的万能引用推导:

  1. 当param为左值时,T为左值引用T&
  2. 当param为右值时,T为非引用T

但是接下来就是一个问题:参数列表的双重引用是如何解决的,即:

  1. 当param为左值时,T为左值引用T&,参数列表为:T& && param
  2. 当param为右值时,T为非引用T,参数列表为:T&& param

第一种情况就是双重引用,需要进行折叠;

折叠引用的条款:如果出现双重引用,则只要其中有一个是左值引用,则整体推断为左值引用。当两个都为右值引用,才会被推导为右值引用;

该条款在forward函数中表现的淋漓尽致;

例如,forward源码如下所示:

template<typename T> T&& forward(typename remove_reference<T>::type& param) {
    return static_cast<T&&>(param);
}

并且搭配完美引用使用:

template<typename T> void f(T&& fparam) {
    //...
    someFunc(std::forward<T>(fparam));
}

例如,f函数内,传入左值和右值widget,之后传入forward函数的形参就有两种:

  1. 左值引用,为widget&
  2. 右值,为widget

当传入forward为左值引用时,T的型别推导为T&,则forward被特例化为:

T& && forward(T& param) {
    return static_cast<T& &&>(param);
}

折叠后发现并没有改变引用形式;

但是当forward为普通类型,T的型别推导为T,则forward被特例化为:

T&& forward(T&& param) {
    return static_cast<T&&>(param);
}

这里注意一下,param相当于直接深拷贝了传入参数,但是其实他是一个左值,因此返回的是他的一个深拷贝;

其他情况:

除了型别推导,还有auto、typedef等情况;

例如:

widget w&;
auto&& a=w;

上述会被推导为:

widget& && a;

即为引用;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值