C++ 中的引用折叠
引言
先来定义一个函数模板,其中的参数是一个右值引用。
template <typename T> void f3(T&&);
f3(42);
正常绑定规则告诉我们可以传递给它右值。那如果
int i =10;
f3(i);
这里给f3调用了左值,按道理这是不ok的,但是C++在正常规则下定义了两个例外规则。
- 第一个例外规则
第一高例外规则影响了右值引用参数的推断,当我们将一个左值传递给函数的右值引用参数,且右值引用指向模板类型参数如(T&&)时,编译器推断类型参数为实参的左值引用类型。
因此,我们调用f3时, 编译器推断T的类型为int&, 而非int。
- 第二个例外规则
第二个例外规则指的是如果我们间接创建了一个引用的引用,则这些引用形成了折叠。
x& &、x& &&和x&& &都会折叠成x&
x&& && 会折叠成x&&
注意:引用折叠只能应用于间接创建的引用的引用,如类型别名或模板参数
f3(i); //实参是一个左值,模板参数T是int&
f3(ci); //实参是一个左值,模板参数T是一个const int&
当模板参数T被推断为战引用类型时,折叠规则则告诉我们T&&是一个左值引用类型。
f3<int&>(a);
//这时候就模板参数等价于int& &&,然后折叠成int&
总结一下结果
- 如果一个函数参数是一个指向模板类型参数的右值引用,则它可以被绑定到一个左值
- 如果实参是一个左值,则推断出来的模板实参类型将是一个左值引用,且函数参数将被实例化为一个普通左值引用参数