C++11右值引用和转发型引用教程详解

2020-01-06 18:30:57丽君

转发型引用

如果某个变量或参数被声明为T&&类型,并且T需要经过推导才可确定,那么这个变量或参数就是一个转发型引用(forwarding reference)。

转发型引用由以下两种语法形式产生

如果某个变量被声明为auto&&类型,那么这个变量就是一个转发型引用 在函数模板中,如果某个参数被声明为T&&类型,并且T是一个需要经过推导才可确定的模板参数类型,那么这个参数就是一个转发型引用

转发型引用是不稳定的,它的实际类型由它所绑定的值来确定。转发型引用既可以绑定左值,也可以绑定右值。如果绑定左值,转发型引用就成了左值引用。如果绑定右值,转发型引用就成了右值引用。
转发型引用在被C++标准所承认之前曾经被称作万能引用(universal reference)。万能引用这一术语的发明者,Effective C++系列的作者Scott Meyers认为,如此异常灵活的引用类型不属于右值引用,它应该拥有自己的名字。

对于某个转发型引用类型的变量(auto&&类型)来说

如果初始化表达式为左值(类型为U&),该变量将成为左值引用(类型为U&)。 如果初始化表达式为右值(类型为U&&),该变量将成为右值引用(类型为U&&)。

对于函数模板中的某个转发型引用类型的形参(T&&类型)来说

如果对应的实参为左值(类型为U&),模板参数T将被推导为引用类型U&,该形参将成为左值引用(类型为U&)。 如果对应的实参为右值(类型为U&&),模板参数T将被推导为非引用类型U,该形参将成为右值引用(类型为U&&)。

struct X {}; 
X&& var1 = X();              // var1是右值引用,只能绑定右值X() 
auto&& var2 = var1;            // var2是转发型引用,可以绑定左值var1 
                      // var2的实际类型等同于左值var1,即X& 
auto&& var3 = X();             // var3是转发型引用,可以绑定右值X() 
                      // var3的实际类型等同于右值X(),即X&& 
template<typename T> 
void g(std::vector<typename T>&& param1); // param1是右值引用 
template<typename T> 
void f(T&& param2);            // param2是转发型引用 
X a; 
f(a);        // 模板函数f()的形参param2是转发型引用,可以绑定左值a 
           // 在此次调用中模板参数T将被推导为引用类型X& 
           // 而形参param2的实际类型将等同于左值a,即X& 
f(X());       // 模板函数f()的形参param2是转发型引用,可以绑定右值X() 
           // 在此次调用中模板参数T将被推导为非引用类型X 
           // 而形参param2的实际类型将等同于右值X(),即X&& 
// 更多右值引用和转发型引用 
const auto&& var4 = 10;              // 右值引用 
template<typename T> 
void h(const T&& param1);             // 右值引用 
template <typename T/*, class Allocator = allocator*/> 
class vector 
{ 
public: 
  void push_back( T&& t );           // 右值引用 
  template <typename Args...> 
  void emplace_back( Args&&... args );     // 转发型引用 
};