2012-09-07 80 views
1

這是一個非常短的代碼片段,它不會用g ++ 4.7.1進行編譯(它不會使用gcc 4.6.3編譯)。爲什麼沒有這個模板函數編譯?

#include <iostream> 

template<typename T> 
struct Foo 
{ 
    template<typename U> 
    friend std::ostream& operator<<(Foo&, U&); 
}; 

template<typename T, typename U> 
std::ostream& operator<<(Foo<T> foo, U& u) 
{ 
    std::cout << u; 
    return std::cout; 
} 

int main() 
{ 
    Foo<int> f; 
    f << "bar"; 
    return 0; 
} 

而這正是GCC 4.7.1輸出(4.6.3說幾乎同樣的事情)。

/tmp/ccNWJW6X.o:在功能main': main.cpp:(.text+0x15): undefined reference to的std :: basic_ostream> & 操作者< <(美孚&,字符常量(&)[4])」 collect2: LD返回1退出狀態

任何人都可以解釋爲什麼?

編輯

我也試圖與鐺3.1,和它說完全一樣的東西。

回答

8

友誼與模板可以是一個有點複雜......讓我們來看看你的代碼作用:

template<typename T> 
struct Foo { 
    template<typename U> 
    friend std::ostream& operator<<(Foo&, U&); // [1] 
}; 
template<typename T, typename U> 
std::ostream& operator<<(Foo<T> foo, U& u) { // [2] 
    std::cout << u; 
    return std::cout; 
} 

當你實例Foo與類型,例如int [1]中聲明瞭一個模板函數的友元聲明:

template <typename U> 
std::ostream& operator<<(Foo<int>&,U&); 

但是,這個功能不存在任何地方,你所提供的[2]是一個模板有兩個參數:

template<typename T, typename U> 
std::ostream& operator<<(Foo<T> foo, U& u); 

關鍵的一點是,朋友聲明,而處理模板正在被實例化,並且此時Foo表示使用當前實例獲得的類型。

有不同的選擇,你想要做什麼,最簡單的是改變了朋友聲明:

template<typename W, typename U> 
friend std::ostream& operator<<(Foo<W> foo, U& u); 

這裏聲明瞭一個模板,以兩個參數(包括WU是綁定在這裏),和火柴您在命名空間級別的定義。

另一種選擇是定義的類模板定義內的友元函數,在這種情況下,你可以保持原有的簽名。有關不同方案的更多信息,看看這個其他answer

1

你實際上並沒有寫輸出操作< < Foo的

注意兩個函數的簽名有很大的不同

相關問題