2011-01-11 112 views
36

我已經閱讀了幾個有關我的問題在stackoverflow現在,並沒有似乎解決我的問題。或者我也許做錯了... 超載<<如果我把它變成一個內聯函數。但是我怎麼讓它在我的情況下工作?重載朋友operator <<模板類

warning: friend declaration std::ostream& operator<<(std::ostream&, const D<classT>&)' declares a non-template function

warning: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here) -Wno-non-template-friend disables this warning

/tmp/cc6VTWdv.o:uppgift4.cc:(.text+0x180): undefined reference to operator<<(std::basic_ostream<char, std::char_traits<char> >&, D<int> const&)' collect2: ld returned 1 exit status

template <class T> 
T my_max(T a, T b) 
{ 
    if(a > b)  
     return a; 
    else 
     return b; 
} 

template <class classT> 
class D 
{ 
public: 
    D(classT in) 
     : d(in) {}; 
    bool operator>(const D& rhs) const; 
    classT operator=(const D<classT>& rhs); 

    friend ostream& operator<< (ostream & os, const D<classT>& rhs); 
private: 
    classT d; 
}; 


int main() 
{ 

    int i1 = 1; 
    int i2 = 2; 
    D<int> d1(i1); 
    D<int> d2(i2); 

    cout << my_max(d1,d2) << endl; 
    return 0; 
} 

template <class classT> 
ostream& operator<<(ostream &os, const D<classT>& rhs) 
{ 
    os << rhs.d; 
    return os; 
} 
+0

有最近關於這可能是有益的一個問題:http://stackoverflow.com/questions/4571611/virtual-operator/ – 2011-01-11 16:52:00

+0

@Daniel - 它不會佔用我爲模板類重載時遇到的問題 – starcorn 2011-01-11 16:55:12

+5

我認爲如果不用給定的答案修改問題會更好。這使得更難確定原來的問題是什麼。你可能想在最後加上一個** EDIT **來解決這個問題,但是我發現當問題發生超時並且我不得不拉起歷史來查看實際上在第一名。 – 2011-01-11 19:13:12

回答

100

這是那些常見問題有不同的方法是相似的,但不是真的一樣。這三種方法在聲明你的功能的朋友 - 然後是你如何實現它的方面有所不同。

外向

申報模板作爲朋友的所有實例。這就是你已經接受的答案,也是大多數其他答案提出的。在這種方法中,你不必要地通過聲明朋友全部operator<<實例來打開你的特定實例D<T>。也就是說,std::ostream& operator<<(std::ostream &, const D<int>&)可以訪問D<double>的所有內部。

template <typename T> 
class Test { 
    template <typename U>  // all instantiations of this template are my friends 
    friend std::ostream& operator<<(std::ostream&, const Test<U>&); 
}; 
template <typename T> 
std::ostream& operator<<(std::ostream& o, const Test<T>&) { 
    // Can access all Test<int>, Test<double>... regardless of what T is 
} 

的內向

只有聲明插入運營商的朋友的特定實例。 D<int>在應用於自身時可能會喜歡插入運算符,但它不希望與std::ostream& operator<<(std::ostream&, const D<double>&)有任何關係。

這可以通過兩種方式來完成,簡單的方法是爲@Emery伯傑提出的,這是內聯的運營商,可呈現也是其他原因是一個好主意:

template <typename T> 
class Test { 
    friend std::ostream& operator<<(std::ostream& o, const Test& t) { 
     // can access the enclosing Test. If T is int, it cannot access Test<double> 
    } 
}; 

在這第一個版本,您是而不是創建模板operator<<,而是模板的每個實例的非模板函數。再一次,這種差異很微妙,但這基本上等同於手動添加:std::ostream& operator<<(std::ostream&, const Test<int>&)當您實例化Test<int>時,以及另一個類似的過載,當您實例化Testdouble或任何其他類型。

第三個版本比較麻煩。如果沒有內聯的代碼,並通過使用模板,你可以聲明模板類的一個朋友的一個實例,而無需打開自己所有其他實例:

// Forward declare both templates: 
template <typename T> class Test; 
template <typename T> std::ostream& operator<<(std::ostream&, const Test<T>&); 

// Declare the actual templates: 
template <typename T> 
class Test { 
    friend std::ostream& operator<< <T>(std::ostream&, const Test<T>&); 
}; 
// Implement the operator 
template <typename T> 
std::ostream& operator<<(std::ostream& o, const Test<T>& t) { 
    // Can only access Test<T> for the same T as is instantiating, that is: 
    // if T is int, this template cannot access Test<double>, Test<char> ... 
} 

以優勢外向型

第三個選項和第一個選項之間的細微差別在於你打開其他類的程度。濫用在外向的版本的一個例子是有人希望得到訪問到你的內部,並做到這一點:

namespace hacker { 
    struct unique {}; // Create a new unique type to avoid breaking ODR 
    template <> 
    std::ostream& operator<< <unique>(std::ostream&, const Test<unique>&) 
    { 
     // if Test<T> is an extrovert, I can access and modify *any* Test<T>!!! 
     // if Test<T> is an introvert, then I can only mess up with Test<unique> 
     // which is just not so much fun... 
    } 
} 
11

你不能聲明這樣一個朋友,你需要指定不同的模板類型吧。

template <typename SclassT> 
friend ostream& operator<< (ostream & os, const D<SclassT>& rhs); 

SclassT所以它不會影classT。當定義

template <typename SclassT> 
ostream& operator<< (ostream & os, const D<SclassT>& rhs) 
{ 
    // body.. 
} 
+0

感謝這篇作品使用這段代碼編輯了我的問題,我會盡快將這個問題作爲答案勾選。 – starcorn 2011-01-11 17:00:25

+4

請注意,這並不是聲明`operator <<`作爲朋友的特定實例,而是** all **實例,包括模板的任何特殊化。看到答案[這裏](http://stackoverflow.com/questions/4660123/overloading-friend-operator-for-template-class/4661372#4661372) – 2011-01-11 19:11:36

2

這對我沒有任何編譯器警告的工作。

#include <iostream> 
using namespace std; 

template <class T> 
T my_max(T a, T b) 
{ 
    if(a > b) 
    return a; 
    else 
    return b; 
} 

template <class classT> 
class D 
{ 
public: 
    D(classT in) 
    : d(in) {}; 

    bool operator>(const D& rhs) const { 
    return (d > rhs.d); 
    } 

    classT operator=(const D<classT>& rhs); 

    friend ostream& operator<< (ostream & os, const D& rhs) { 
    os << rhs.d; 
    return os; 
    } 

private: 
    classT d; 
}; 


int main() 
{ 

    int i1 = 1; 
    int i2 = 2; 
    D<int> d1(i1); 
    D<int> d2(i2); 

    cout << my_max(d1,d2) << endl; 
    return 0; 
} 
0

在這裏你去:

#include <cstdlib> 
#include <iostream> 
using namespace std; 

template <class T> 
T my_max(T a, T b) 
{ 
    if(a > b)  
     return a; 
    else 
     return b; 
} 

template <class classT> 
class D 
{ 
public: 
    D(classT in) 
     : d(in) {}; 
    bool operator>(const D& rhs) const { return d > rhs.d;}; 
    classT operator=(const D<classT>& rhs); 

    template<class classT> friend ostream& operator<< (ostream & os, const D<classT>& rhs); 
private: 
    classT d; 
}; 

template<class classT> ostream& operator<<(ostream& os, class D<typename classT> const& rhs) 
{ 
    os << rhs.d; 
    return os; 
} 


int main() 
{ 

    int i1 = 1; 
    int i2 = 2; 
    D<int> d1(i1); 
    D<int> d2(i2); 

    cout << my_max(d1,d2) << endl; 
    return 0; 
} 
0

我覺得你不應該讓朋友擺在首位。

您可以創建一個公共方法調用打印,這樣的事情(對非模板類):

std::ostream& MyClass::print(std::ostream& os) const 
{ 
    os << "Private One" << privateOne_ << endl; 
    os << "Private Two" << privateTwo_ << endl; 
    os.flush(); 
    return os; 
} 

,然後在類外(但在同一個命名空間)

std::ostream& operator<<(std::ostream& os, const MyClass& myClass) 
{ 
    return myClass.print(os); 
} 

我認爲它也適用於模板類,但我還沒有測試過。