2016-09-30 70 views
1
#include <iostream> 

template <typename T> 
class test 
{ 
public: 
    test(T&& t) 
    { 
    } 
}; 

template <typename T> 
void succeed(T&& t) 
{ 
} 

int main() 
{ 
    int i = 1; 
    test<int> t(i); // failed to compile 
    succeed(i);  // OK 
    return 0; 
} 

錯誤從GCC 5.2: main.cpp中:在函數 '詮釋主()': main.cpp中:20:18:錯誤:不能結合 'INT' 左值to'int & &' test t(i); ^ main.cpp中:7:5:注:初始化的參數1 '測試::測試(T & &)[用T = INT]' 測試(T & &噸) ^ ~~~右值參考VS功能模板

有人可以解釋爲什麼類模板不能編譯,但功能模板是可以的嗎? 謝謝。

+0

如果我們真的知道你得到的錯誤,這將更容易解釋。發佈有關構建錯誤的問題時,請始終在問題的主體中包含完整的和未經編輯的完整錯誤輸出。請修改您的問題以包含該問題。還請包括您正在使用的編譯器以及它的哪個版本。 –

回答

3

您的困惑可能源於您的假設,在這兩種情況下,Tint。這就是爲什麼你認爲這兩種情況相似。事實上他們不是。

在班級版本中,您正在手動指定T是什麼。你明確告訴編譯器Tint。在這種情況下,構造函數參數類型T &&變爲int &&,它不能綁定到常規左值。因此錯誤。

在函數版本中,你不會告訴編譯器什麼是T,而是你期望編譯器能夠推導出它。在像你這樣的情況下,語言故意設計爲推導Tint &(注意:不是int,而是int &)。一旦T被推導爲int &,所謂的"reference collapsing" rules導致函數參數類型T &&變爲int &-普通的左值參考。該參數可以成功綁定到左值參數i

這解釋了您觀察到的差異。

爲了實驗的緣故,在後一種情況下,你可以抑制模板參數推導,並指定模板參數明確

succeed<int>(i); 

這將有力地指定Tint,並導致同樣的錯誤作爲因爲同樣的原因,

同樣,你可以通過指定模板參數爲int &

test<int &> t(i); 

「模擬」類函數的行爲相同的「參考崩潰」的規則將使您的構造函數調用成功編譯。

4

succeedT&& t轉發參考,而不是一個右值引用。但在test,它是一個右值參考。

轉發參考僅在參數爲T&&時發生,並且T是該函數的模板參數。在您的代碼中,T是封閉類的模板參數,因此它不被視爲轉發參考。

轉發參考可能綁定到左值和右值。

在起草C++ 11時,建議使用不同的語法來轉發引用而不是右值引用(而不是使用T&& t);然而委員會最終決定了目前的行爲。

有關模板參數推演的更詳細說明,包括T&&成爲轉發參考時的更精確規範,see here - 搜索術語「轉發參考」以查找轉發參考的特殊規則。