您的位置:首页 > 其它

std::forward(expr)参数推导

2016-03-20 14:06 204 查看
对于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

来源:知乎

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: