2009-08-19 11 views
27

Próbuję przeciążać operatora < < jako znajomego, aby klasy szablonu Pair, ale wciąż otrzymuję ostrzeżenie kompilatora mówiącPrzeciążenie operatora przyjaciel << dla klasy szablonu

friend declaration std::ostream& operator<<(ostream& out, Pair<T,U>& v) declares a non template function 

na ten kod:

friend ostream& operator<<(ostream&, Pair<T,U>&); 

daje drugie ostrzeżenie jako zalecenie mówiąc

if this is not what you intended, make sure the function template has already been declared and add <> after the function name here 

Oto definicja funkcji: i tutaj jest cała klasa.

template <class T, class U> 
class Pair{ 
public: 
    Pair(T v1, U v2) : val1(v1), val2(v2){} 
    ~Pair(){} 
    Pair& operator=(const Pair&); 
    friend ostream& operator<<(ostream&, Pair<T,U>&); 

private: 
    T val1; 
    U val2; 
}; 

Nie byłem pewien, co wyciągnąć z ostrzeżenia o zaleceniu, poza tym, że być może muszę umieścić gdzieś w deklaracji przyjaciela. Czy ktokolwiek zna odpowiednią składnię tego? Dzięki.

Odpowiedz

19

zadeklarować operatora < < jako zwrócenie ostream &, ale nie ma w ogóle return w metodzie. Powinno być:

template <class T, class U> 
ostream& operator<<(ostream& out, Pair<T,U>& v) 
{ 
    return out << v.val1 << " " << v.val2; 
} 

Poza tym, nie mam żadnych problemów lub ostrzeżenia kompilacji kodu pod Visual Studio 2008 z ostrzeżeniami na poziomie 4. Oh, istnieją klasyczne błędy łącznikowe, ale to jest łatwo obejść poprzez przesunięcie definicja funkcji szablonu do deklaracji klasy, jak wyjaśniono w C++ FAQ.

Mój kod testowy:

#include <iostream> 
using namespace std; 

template <class T, class U> 
class Pair{ 
public: 
    Pair(T v1, U v2) : val1(v1), val2(v2){} 
    ~Pair(){} 
    Pair& operator=(const Pair&); 
    friend ostream& operator<<(ostream& out, Pair<T,U>& v) 
    { 
     return out << v.val1 << " " << v.val2; 
    } 
private:  
    T val1; 
    U val2; 
}; 

int main() { 
    Pair<int, int> a(3, 4); 
    cout << a;  
} 
44

Chcesz zrobić pojedynczą instancję (zwaną "specjalizacją" w kategoriach ogólnych) tego szablonu znajomemu. Zrobisz to w następujący sposób

template <class T, class U> 
class Pair{ 
public: 
    Pair(T v1, U v2) : val1(v1), val2(v2){} 
    ~Pair(){} 
    Pair& operator=(const Pair&); 
    friend ostream& operator<< <> (ostream&, Pair<T,U>&); 

private: 
    T val1; 
    U val2; 
}; 

ponieważ kompilator wie z listy parametrów, że argumenty szablonu zostaną T i U, nie trzeba umieścić te między <...>, więc mogą być pozostawione puste. Należy pamiętać, że trzeba umieścić deklarację operator<< powyżej szablonie Pair, jak następuje:

template <class T, class U> class Pair; 

template <class T, class U> 
ostream& operator<<(ostream& out, Pair<T,U>& v); 

// now the Pair template definition... 
+9

+1 To jest rzeczywiście to, co kompilator narzeka. Druga odpowiedź dotyczy problemu z obejściem: zamiast informowania kompilatora o tym, że przyjaciel jest specjalizacją szablonu, tworzy on niewymiarową funkcję << operatora dla podanych typów. –

+0

Zgadzam się z Davidem; jest to najlepsze rozwiązanie w zakresie najlepszej praktyki i dobrego programowania. – Andry

+1

Wow, dodatkowe '<>' jest łatwe do przegapienia! – Nick

1

Prosta wersja inline:

template<typename T> class HasFriend { 
    private: 
     T item; 
    public: 
     ~HasFriend() {} 
     HasFriend(const T &i) : item(i) {} 
    friend ostream& operator<<(ostream& os, const HasFriend<T>& x) { 
     return os << "s(" << sizeof(x) << ").op<<" << x.item << endl; 
    } 
}; 

Zmieniona wersja szablonu:

template<template<typename /**/> class U, typename V> 
ostream& operator<<(ostream &os, const U<V> &x) { 
    return os << "s(" << sizeof(x) << ").op<<" << x.item << endl; 
} 

template<typename T> class HasFriend { 
    private: 
     T item; 
    public: 
     ~HasFriend() {} 
     HasFriend(const T &i) : item(i) {} 
    friend ostream& operator<<<>(ostream&, const HasFriend<T>&); 
}; 
Powiązane problemy