std::forward(expr)参数推导

本文详细解析了C++中forward函数实现的完美转发原理,包括如何通过模板和remove_reference帮助实现左引用和右引用的正确传递,以及在不同引用情况下如何保持原始引用类型。
对于forward,其boost的实现基本可以等价于这样的形式:

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

那么这里面是如何达到完美转发的呢?

举一个栗子

template<typename T>
void foo(T&& fparam)
{
    std::forward<T>(fparam);
}

int i = 7;
foo(i);
foo(47);

如上文所述,这里的i是一个左值,于是,我们在void foo(T&& fparam)这里的话,T将会被deduce成int& 然后Param Type为int&。(注意,我这里使用的变量名字为fparam,以便与forward的param进行区分)

那么为什么Param Type会是int&呢?因为按照正常的deduce,我们将会得到

void foo(int& &&fparam);

先前我简单的提到了一句,C++不允许reference to reference,然而事实上,我们却会出现Lvalue reference to Rvalue reference[1], Lvalue reference to Lvalue reference[2], Rvalue reference to Lvalue reference[3], Rvalue reference to Rvalue reference[4]等四种情况,那么针对这样的情况,编译器将会根据引用折叠规则变为一个Single Reference,那么是左值引用还是右值引用呢?其实这个规则很简单,只要有一个是左值引用,那么结果就是左值引用,其余的就是右值引用。于是我们知道了[1][2][3]的结果都是左值引用,只有[4]会是右值引用,而要从

void foo(T&& fparam)

这里T的Universal Reference让fparam拥有右值引用类型,那么则需要保证传递归来的参数为右值才可以,因为若是左值的话,T会deduce成左值引用,结合引用折叠规则,fparam的类型会是左值引用类型。

于是我们现在来看,int& &&这样的情况属于Lvalue reference to Rvalue reference,结果则为左值引用。那么,我们这个时候带入到forward函数来看看,首先是T变为了int&,经过了remove_reference变为了int,结合后面跟上的&,则变为了int&。然后我们再次替换 static_cast和return type的T为int&,都得到了int& &&

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

于是再应用引用折叠规则,int& &&都划归为了int&

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

于是,我们可以发现我们fparam变量的左值引用类型被保留了下来。这里也需要注意,我们到达forward的时候就已经是左值引用了,所以forward并没有改变什么。

如我们这时候是47这样的右值,我们知道了T会被deduce成int,经过了remove_reference,变为了int,跟上后面的&,成为了int&,然后再次替换static_cast和返回类型的T为int&&

int && forward(int& param)
{
    return static_cast<int&&)(param);
}

于是,我们也可以发现,我们fparam变量的右值引用类型也完美的保留了下来。

更权威和详细的解释楼主可以阅读Effective Modern C++,那是本好书,我也只是把Meyers的观点简要的提炼了一下。


作者:蓝色
链接:https://www.zhihu.com/question/34544004/answer/59104471
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值