2013-06-12 30 views
1

只是一個問題,我發現有趣的時候使用STL。在下面的代碼中,主函數中的最後兩行會導致錯誤(在註釋中指示)。但是,test_func編譯得很好。由於傳遞給模板函數的類型是引用類型,並且函數本身適用於這兩個操作符,所以這兩個操作符本質上不是相同的嗎?好吧,顯然不會導致其中一個編譯,而另一個不會。有人知道爲什麼C++嵌套引用直接vs通過模板參數

class File { 

    private: 
      std::string name_; 

    public: 

      File(std::string n) : name_(n) {} 
      std::string name() const { return name_; } 
}; 

std::ostream& operator<<(std::ostream& os, const File& f) 
{ 
    os << f.name(); 
    return os; 
} 

template <class T> void test_func(const T& v) 
{ 
    T& v1(v); 
    std::cout << "File:" << v1 << std::endl; 
} 

typedef File& FileRef; 

int main(int argc, char* argv[]) 
{ 
    File f("test_file"); 
    test_func<File&>(f); 
    // FileRef& fRef1(f); ==> error; cannot declare reference to 'class File&' 
    // File&& fRef2(f);  ==> error; expected unqualified-id before '&&' token 

} 

更新:我在處理bind1st和bind2nd函數時遇到了這個問題;它們在文本書中定義就像test_func一樣(第18章關於活頁夾的stroustrup),所以它不會出錯。

+0

其即使我用 FileRef&fRef1 = F相同的錯誤; File && fREf2 = f; –

回答

2

第一條註釋行是合法的,您的編譯器可能不符合C++ 11。由於C++ 11的引用崩潰規則,事實上,它應該聲明一個名爲fRef1File的左值引用,並將其綁定到左值f

第二條註釋行是非法的:您不能將左值引用綁定到左值。但是,您收到的錯誤似乎表明編譯器不理解&&令牌。

如果您使用的是Clang或GCC,請確保您正在編譯-std=c++11-std=c++0x選項。

UPDATE:

在C++ 03,這兩條線是非法的,並且甚至這種函數調用應該被編譯器拒絕:

test_func<File&>(f); // SHOULD BE AN ERROR! (substitution failure) 

每一段的14.8.2/2在C++ 03標準:

[...]類型推導失敗可能 原因如下:

- [...]

- 試圖創建以引用類型或作廢的基準的基準。

- [...]

這可能意味着兩件事情:要麼你的編譯器有一個bug,或者故意決定忽視試圖創建模板實參推演的背景下,參考參考(並且只在這種情況下) - 意味着你正在處理一個編譯器擴展。

在任何情況下,該函數調用不合格,因此不可移植。

+0

我正在使用gcc版本4.4.6。所以,如果我不使用C++ 11第一行是非法的權利?如果是這樣,爲什麼test_func成功?它與第一行有什麼不同? –

+0

@PurushothamNayak:對不起,我以前的評論是不正確的。該函數調用應該也是非法的 –

0

我認爲這個函數有效,因爲編譯器足夠聰明,不會引用一個引用。他得到一個參考,並希望有一個參考,所以它保持一個。我想他只是忽略了第二個&當你有T &與T已經是一個參考。 我不能詳細解釋它,但在C++中,您可以使用大多數非常類似於非引用的引用。

FileRef&他不能忽視這一點。在這裏你明確地說:做一個參考的參考,什麼不能工作。 和& &是一個邏輯與。

PS:取代失敗不是錯誤(SFINAE)

+0

但是如果替換失敗後沒有可用的過載,那就是錯誤。 – aschepler