template<typename T> void f3(T&&);
int I;
const int ci;
f3(42); //实参是一个int右值;模板参数T是int(正常的普通推断)
f3(i); //实参是左值;模板参数T是int&
f3(ci); //实参是左值;模板参数T是一个const int&
1. 除了两个例外,C++不允许将一个右值引用绑定到一个左值上
a. 第一个例外规则影响右值引用参数的推断如何进行:当我们将一个左值(如i)传递给函数的右值引用参数,且此右值引用指向模板类型参数(如T&&)时,编译器推断模板类型参数为实参的左值引用类型。
b. 通常我们不能(直接)定义一个引用的引用。但是,通过类型别名或通过模板类型参数间接定义是可以的。
c. 第二个例外绑定规则:如果我们间接创建一个引用的引用,则这些引用形成了“折叠”。除了一个例外,其他所有情况下,引用会折叠成一个普通的左值引用类型。在新标准中,折叠规则扩展到右值引用。只有一种特殊情况下引用会折叠成右值引用:右值引用的右值引用。即,对于一个给定类型X:
i. X& &、X& &&和X&& &都折叠成类型X&
ii. 类型X&& &&折叠成X&&
注 | 引用折叠只能应用于间接创建的引用的引用(包括左值引用的左值引用、右值引用的右值引用 |
注 | 当一个变量本身的类型是引用类型的时候,这种情况下,类型当中所带的引用就被忽略了. 来自 <https://blog.csdn.net/guangcheng0312q/article/details/103572987> |
2. 将引用折叠规则和右值引用的特殊类型推断规则组合,则意味着:
a. 如果一个函数参数是一个指向模板类型参数的右值引用,(如,T&&),则它可以被绑定到一个左值;
b. 如果实参是一个左值,则推断出的模板实参类型将是一个左值引用,且函数参数将被实例化为一个(普通)左值引用参数(T&
注 | 这暗示可以传递任意类型的实参给T&&类型的函数参数 |