C++11標(biāo)準(zhǔn)頒布距今已經(jīng)十年了,在這個標(biāo)準(zhǔn)中引入了很多新的語言特性,在進(jìn)一步強化C++的同時,也勸退了很多人,其中就包含右值引用。
T&& Doesn’t Always Mean “Rvalue Reference”
by Scott Meyers
Scott Meyers曾經(jīng)說過:T&&并不總是表示右值引用(rvalue reference)。
作為函數(shù)參數(shù)的&&
沒錯。&& 這兩個符號,可能是初學(xué)C++或者C++11的時候,把很多人勸退的一個點。但想理清其實也不難。
首先在非模板函數(shù)中,&&肯定是表示右值引用,所以只能接收右值類型的參數(shù)。
class A {
...
};
void foo(A&& a) {
...
}
這個foo函數(shù)只能接受如下的右值參數(shù)。
foo(A{});
A a;
foo(std::move(a));
A get_a() {
A a;
...
return a;
}
foo(get_a());
但是這樣調(diào)用則不正確,會編譯失敗:
A a1;
A& ar = a1;
foo(ar); // ERROR
但是,在模板函數(shù)中&&則并不表示右值引用(rvalue rference)。比如:
template <typename T>
void bar(T&& t) {
...
}
這個T&&在C++標(biāo)準(zhǔn)中被稱為forwarding reference, 譯作轉(zhuǎn)發(fā)引用, 俗稱(非官方習(xí)慣但流行的叫法)是 universal reference,經(jīng)常被譯作萬能引用。顧名思義,它所能接收的參數(shù)不僅僅是右值,左值也可以,故稱萬能。所以題主問題中的是T&&并不是右值引用。
我上文提到的模板函數(shù)bar(),可以接收如下類型的的參數(shù)(各種類型都可以?。1热纾?/p>
bar(A{});
A a;
bar(move(a));
bar(get_a());
A a1;
A& ar1 = a1;
bar(ar1);
const A& ar2 = a1;
bar(ar2);
但是模板函數(shù)中的&&也不全是轉(zhuǎn)發(fā)引用。比如:
template<typename T>
void bar(vector<T>&& tv) {
...
}
這里的參數(shù)tv就只能接收右值類型的參數(shù)。
又比如:
template<typename T>
void bar(const T&& v) {
...
}
加了const限制后,這里的&&也是右值引用,只能傳入右值……
相信你已經(jīng)看懂其中的差別。
接收返回值的&&
&&迷惑的另一個地方不僅在于上面介紹的,作為參數(shù)的時候。在接收函數(shù)返回值的時候,也有歧義,常常讓人迷惑。
class A {
...
};
A&& a = test1(); // 這個&&表示的是右值引用
auto&& a = test2(); // 這個&&表示的是也是轉(zhuǎn)發(fā)引用
在auto和&&聯(lián)用的時候,它也是轉(zhuǎn)發(fā)引用(萬能引用),故而可以接收各種類型的函數(shù)參數(shù)。
但是如果是顯式指定了類型(比如A)然后和&&聯(lián)用,則只表示右值引用,只能接收右值類型的參數(shù)!
怎么樣,勸退了沒。
