T&&
在代碼裏並不老是右值引用:c++
void f(Widget&& param); // rvalue reference Widget&& var1 = Widget(); // rvalue reference auto&& var2 = var1; // not rvalue reference template<typename T> void f(std::vector<T>&& param); // rvalue reference template<typename T> void f(T&& param); // not rvalue reference
T&&
表明兩種含義:函數
萬能引用通常出如今兩個場景中:設計
template<typename T> void f(T&& param); // param is a universal reference
auto&& var2 = var1; // var2 is a universal reference
咱們分別討論下這兩種場景。code
咱們注意到,涉及到萬能引用的地方,都會有參數推導的過程,例如上面的T和var2. 而右值引用則沒有這個過程:get
void f(Widget&& param); // no type deduction; param is an rvalue reference Widget&& var1 = Widget(); // no type deduction; var1 is an rvalue reference
可是即便語句設計到參數推導,也不必定就是萬能引用。例如:io
template<typename T> void f(std::vector<T>&& param); // param is an rvalue reference std::vector<int> v; f(v); // error! can't bind lvalue to rvalue reference
這點仍是比較好理解的。萬能引用須要依靠表達式來初始化本身是右值引用仍是左值引用,可是上面這個例子沒有表現出這一點,它僅僅是推斷了T的類型,可是param的類型一直都是std::vector<T>&&
。模板
咱們再舉一個vector中的例子:class
template<class T, class Allocator = allocator<T>> class vector { public: void push_back(T&& x); // rvalue reference template <class... Args> void emplace_back(Args&&... args); // universal reference };
push_back(T&& x)
中的T&&爲右值引用,由於這個雖然是T&&,可是不涉及到參數推導。當push_back被instantiated時,實際的調用相似於:std::vector<Widget> v; ... class vector<Widget, allocator<Widget>> { public: void push_back(Widget&& x); // rvalue reference … };
能夠很明顯的看出此時沒有參數推導的過程。sed
template <class... Args> emplace_back(Args&&... args)
中的Args&&
爲萬能引用。Args與T是相互獨立的,因此Args有一個獨立的參數推斷過程。有意思的是,當參數加上const後,就必定是右值引用:lambda
template <class T> int f(T&& heisenreference); template <class T> int g(const T&&); int i; int n1 = f(i); // calls f<int&>(int&) int n2 = f(0); // calls f<int>(int&&) int n3 = g(i); // error: would call g<int>(const int&&), which would bind an rvalue reference to an lvalue
至於爲何會有這個規定,按照Why adding const
makes the universal reference as rvalue的說法,大致有兩點緣由:
const T&&
容許你重載一個函數模板,它只接受右值引用。若是const T&&
也被當作universal reference,那麼將沒有辦法讓函數只接受右值引用。template <typename T> void cref(const T&&) = delete;
對於auto的場景來講,全部的auto&&
都是萬能引用,由於它老是有參數推導的過程。例如定義一個記錄函數執行時間的lambda(C++14中容許使用auto來聲明lambda的函數):
auto timeFuncInvocation = [](auto &&func, auto &&... params) { start timer; std::forward<decltype(func)>(func)( // invoke func std::forward<decltype(params)>(params)... // on params ); stop timer and record elapsed time; };
(完)
朋友們能夠關注下個人公衆號,得到最及時的更新: