2016-11-26 37 views
17

右值引用和轉發引用之間的區別作出足夠清楚在這個例子斯科特邁爾斯:這是一個轉發參考?

Widget&& var1 = someWidget;  // here, 「&&」 means rvalue reference (1) 

auto&& var2 = var1;    // here, 「&&」 does not mean rvalue reference (2) 

template<typename T> 
void f(std::vector<T>&& param); // here, 「&&」 means rvalue reference (3) 

template<typename T> 
void f(T&& param);    // here, 「&&」does not mean rvalue reference (4) 

本質上的區別發生時,我們有一個抵扣方面,因此情況(3)明確規定,我們具有vector<...>&&,而情況(4)中的T將被推斷並且(在應用參考摺疊規則之後)按照「價值類別」進行分類。

但是,有點複雜的模式匹配會發生什麼?就拿下面的情況:

template <template <class...> class Tuple, class... Ts> 
void f(Tuple<Ts...>&& arg) 
{ 

} 

是什麼意思&&這裏?

+1

可推論的上下文並不重要。 (3)和(4)都可以推導出來。 – Oktalist

回答

14

在上例中,arg是一個右值引用。

轉發參考是一個rvalue參照CV-不合格模板參數

Tuple<Ts...>不是模板參數。

(引文從[temp.deduct.call]。)

9

它是一個右值引用,而不是轉發參考。

,以確保最簡單的方法是嘗試通過一個左值,如果失敗的話,那麼它是一個右值引用,如果沒有,那麼轉發參考:

template<typename... Ts> 
struct foo {}; 

//f function definition 

int main() { 
    foo<int, double> bar; 
    f(bar); // fails! Cannot bind lvalue to rvalue reference 
    f(foo<int, double>{}); // ok, rvalue is passed 
} 
1

概念轉發引用不是一個標準的概念,當你看到它的時候它是有用的,但是如果你想正確地理解和處理它,你必須理解參考算法。(我相信梅爾的書也有一個關於它的章節)

什麼是轉發引用的概念背後是基準運算:

  • & & & & = & &
  • & & & = &
  • & & & = &
  • & & = &

讓我們模擬編譯器模板類型扣除與轉發參考

template<class T> 
void foo(T&&); 
//... 
const int i=42; 
foo(i); // the compiler will defines T = const int & 
     //   T&& = const int & && = const int & 
     // => the compiler instantiates void foo<const int &>(const int &); 
foo(6*7);// the compiler will defines T = int 
     //   T&& = int && 
     // the compiler instantiates void foo<int>(int &&); 

在這種情況下,模板foo的實例化可以產生 的函數由左值引用或帶參數的函數引用參數右值引用:轉發引用是 一個右值引用或一個左值引用,取決於模板類型的扣除。它被命名爲這樣的,因爲在這種情況下,該參數應是作爲一個左或作爲x值過去了,這是T&& std::forward<T>(T&& a)

的工作,如果你定義一個函數有:

template<class T> 
void foo(ATemplateClass<T> && a); 

無論編譯器爲T推導出什麼類型,都會得到一個右值引用參數。

+0

你確定你的樣品?我相信foo(42)和foo(6 * 7)在這裏是同一條船:https://godbolt.org/g/jOEK9b – RTempete

+0

@RTempete這篇文章的一部分似乎是錯誤的:正如你所看到的,兩者推導到'int &&' - 相同,而不是'const'。如果Oliv會解釋爲什麼他們認爲兩者應該是「常量」,並且/或者基於是否涉及(即使在'-O0'表達式中是微不足道的,優化的),也應該存在一些差異,那將會更多有用。 –

+0

對不起,在例程代碼中有兩個錯誤。 f(42) - >右值參考和f(6 * 7)。 – Oliv