- 引子
- 如何區分
- 模板引數
- const disqualify universal reference
- auto宣告
- 模板引數
引子
T&&在代碼里并不總是右值參考:
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&&代表兩種含義:
- 右值參考
- 萬能參考(universal references, or forwarding references)
如何區分
萬能參考一般出現在兩個場景中:
- 模板引數
template<typename T>
void f(T&& param); // param is a universal reference
- auto宣告
auto&& var2 = var1; // var2 is a universal reference
我們分別討論下這兩種場景,
模板引數
我們注意到,涉及到萬能參考的地方,都會有引數推導的程序,例如上面的T和var2. 而右值參考則沒有這個程序:
void f(Widget&& param); // no type deduction; param is an rvalue reference
Widget&& var1 = Widget(); // no type deduction; var1 is an rvalue reference
但是即使陳述句設計到引數推導,也不一定就是萬能參考,例如:
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中的例子:
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
…
};
可以很明顯的看出此時沒有引數推導的程序,
template <class... Args> emplace_back(Args&&... args)中的Args&&為萬能參考,Args與T是相互獨立的,所以Args有一個獨立的引數推斷程序,
const disqualify universal reference
有意思的是,當引數加上const后,就一定是右值參考:
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的場景來說,所有的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;
};
(完)
朋友們可以關注下我的公眾號,獲得最及時的更新:

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/228337.html
標籤:C++
