引用折叠
c++中有明确含义的引用只有两种,一种是&左值引用,一种是带&&右值引用。类似void myfunc(T &&tmprv),T和tmprv的&&就被分为两组,一组是T,另一组是&&。那么这两组就有以下四种情况
第一组 | 第二组 | 引用折叠结果 |
---|---|---|
& | & | & |
& | && | & |
&& | & | & |
&& | && | && |
注意:引用折叠有以下规则,如果任意一组引用为左值引用,由于左值引用会传染,那么引用折叠后的结果就是左值引用,否则就是右值引用
引用的引用
概念:int& &tmprv,类似这种写法,叫做引用的引用,编译器内部再进行模板类型推断的时候,可能出现引用的引用这种情况,这个时候编译器会用引用折叠规则处理,但是编译器不允许你在程序开发中直接写出引用的引用这种形式的代码
完美转发
一个函数模板如果能把收到的参数以及这些参数相对应的类型(比如左值引用,右值引用,加没加const)不变的转发给其他函数,就称为这个函数模板实现了完美转发
注意,万能引用可以把实参的所有信息都收集起来(除了右值的特性,我们仍需注意,右值引用变量本身是一个左值),所以完美转发用到了万能引用
所以,完美转发除了要用到万能引用,还得用到std::forward
std::forward
这是一个帮助函数,允许将作为右值引用的参数完美地转成推导的右值类型,保留任何可能涉及的移动语义
template<typename FUN,typename T1,typename T2>
void func(FUN fun,T1&& t1,T2&& t2)
{
fun(::std::forward<T1>(t1),::std::forward<T2>(t2));
}
void hello(int&&t1,int &t2)
{
}
int i=10;
func(hello,20,i);
因为模板类型T1和模板类型T2中,保留了调用模板函数的实参类型信息,即,forward需要知道原来的实参(传给函数模板func的实参)是左值还是右值,所以::std::forward<T1>()和::std::forward<T2>是必须的,forward的能力是保持原始实参的类型