T&&
类型推导上下文中的句法形式(包括模板参数推导,但例如也推导声明为的变量的类型auto
)并不表示右值引用,而是斯科特迈耶斯所说的[通用引用]。请注意,只有非常特殊的句法形式 T&&
表示通用引用,而其他类似的形式不被视为如此。例如:
template<typename T>
void foo(T&& t); <-- T&& is a universal reference
template<typename T>
void foo(T const&& t); <-- T const&& is NOT a universal reference
template<typename T>
void foo(S<T>&& t); <-- S<T>&& is NOT a universal reference
template<typename T>
struct S { void foo(T&& t); }; <-- T&& is NOT a universal reference
通用引用可以绑定到左值和右值。如果A
绑定了类型的左值,则T
推断为 be并且由于引用折叠规则(变为) A&
,参数的类型解析为(左值引用)。如果绑定了类型的右值,则推断为,并且参数的类型解析为(右值引用)。A&
A& &&
A&
A
T
A
A&&
[注意:引用折叠规则可能看起来很复杂,但实际上非常简单:引用 Stephan T. Lavavej 的话,“左值引用具有传染性”,这意味着当表单T&& &
、T& &
或T& &&
被实例化时,它们总是解析为T&
- 只有表单T&& &&
被解析为T&&
]
这就是为什么当参数是左值std::move
时函数模板将被实例化如下(推导为 be ):T
T&
typename remove_reference<A&>::type&& std::move(A& && a);
而当参数是右值时,它将被实例化如下(T
推导为A
)
typename remove_reference<A>::type&& std::move(A&& a);