Table of contents
1-1--The realization of universal reference
1-2--The difference between universal reference and rvalue reference
1--Universal reference
1-1--The realization of universal reference
A universal reference can pass any type of parameter to it , and it will automatically infer the parameter type ; the two implementations of the universal reference are as follows:
// 基于模板实现
template <typename T>
void f(T&& v){
}
// 基于auto实现
auto && v2 = v1;
1-2--The difference between universal reference and rvalue reference
Different from using the above two methods to implement universal references (requiring type inference ) (C++ Primer also refers to universal references based on templates as rvalue references of a template type parameter ), in plain English, the type of rvalue references is deterministic , for example, the following are rvalue references with definite types :
int &&
char &&
std::string &&
An rvalue reference itself is an lvalue , but it can only bind rvalues ;
Universal references can bind lvalues , rvalues , and even const objects and non-const objects;
2--Reference folding
In the template implementation of the universal reference above, when different types T are passed, reference folding often occurs ; when the passed parameter is a reference, the type T inferred by the template will be a reference to the reference , and then reference will occur fold;
In the template implementation of the universal reference, the rules of reference folding are as follows:
① When the passed parameter is an lvalue , the type T inferred by the template will be an lvalue reference ;
② When the passed parameter is a literal value , the type T inferred by the template will be the type of the literal value ;
③ In all cases (one exception, explained in point ④), the result of reference folding is an ordinary lvalue reference type;
④ But when the object of reference folding is an rvalue reference , the result of reference folding is an rvalue reference type;
// 基于模板实现
template <typename T>
void f(T&& v){
}
int x = 1;
f(x); // x是一个左值,则 T 的推断结果是左值引用: int &
f(1); // 1是一个字面值,则 T 的推断结果是字面值的类型: int
int&& y = 1;
f(y); // y是一个右值引用,则 T 的推断结果是: int, T && 等价于 int &&;
// 对于一个给定的类型 X
X& &, X& &&, X&& & 都会折叠成X&,
即int& &, int& &&, int&& & 都会折叠成(等价于)int&
类型X&& && 则会折叠成 X&&,
即 int&& && 会折叠成(等价于)右值引用: int&&