2010-10-28 8 views
37

Posiadam klasę bazową zbliżoną do poniższego kodu. Próbuję przeciążać < < do użycia z cout. Jednak g ++ mówi:Deklaracja przyjaciela deklaruje funkcję bez szablonu

base.h:24: warning: friend declaration ‘std::ostream& operator<<(std::ostream&, Base<T>*)’ declares a non-template function 
base.h:24: 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 

Próbowałem dodanie <> po < < w deklaracji klasy/prototypu. Jednak otrzymuję go does not match any template declaration. Starałem się, aby definicja operatora była w pełni szablonowana (co chcę), ale udało mi się ją uruchomić tylko z następującym kodem, z ręcznym tworzeniem operatora.

base.h

template <typename T> 
class Base { 
    public: 
    friend ostream& operator << (ostream &out, Base<T> *e); 
}; 

base.cpp

ostream& operator<< (ostream &out, Base<int> *e) { 
    out << e->data; 
return out; 
} 

Chcę po prostu mieć to lub podobne w nagłówku, base.h:

template <typename T> 
class Base { 
    public: 
    friend ostream& operator << (ostream &out, Base<T> *e); 
}; 

template <typename T> 
ostream& operator<< (ostream &out, Base<T> *e) { 
    out << e->data; 
return out; 
} 

mam przeczytaj gdzie indziej online, w którym wstawianie <> pomiędzy < < i() w prototypie powinno napraw to, ale tak nie jest. Czy mogę to zrobić w jednym szablonie funkcji?

+4

To dokładnie problem rozwiązany przez Dan Saks' [ "nowych przyjaciół" idiom] (http://en.wikibooks.org/wiki/More_C % 2B% 2B_Idioms/Making_New_Friends). _ (Przepraszam za spóźniony komentarz.) _ –

Odpowiedz

29

Brzmi jak chcesz zmienić:

friend ostream& operator << (ostream& out, const Base<T>& e); 

Do:

template<class T> 
friend ostream& operator << (ostream& out, const Base<T>& e); 
+17

Więc nie wierzyłem ci, ale to działa. Jednak nie mogę użyć 'T', ponieważ' cienie' na istniejącym już 'T' szablonu klasy. –

+1

Czy GCC daje ci ostrzeżenie o cieniu? –

+5

Tak, GCC ostrzegł o shadowingu. Zastąpiłem T przez Y i to rozwiązało. 'error: shadows template parm 'class T'' –

-3

zmiana

ostream& operator<< (ostream &out, Base<int> *e) { 
    out << e->data; 
    return out; 
} 

do

ostream& operator<< (ostream &out, T *e) { 
    out << e->data; 
    return out; 
} 
+0

To na pewno nie zadziała. Oprócz podania 'employee.cpp: 32: error: 'T' nie został zadeklarowany w tym zakresie', nawet po utworzeniu szablonu w pliku .h lub .cpp, nie zadziała z powodu niezdefiniowanych symboli podczas łączenia. Ponadto wciąż otrzymuję ostrzeżenie. Chcę, aby był jak normalny szablon zdefiniowany w pliku nagłówkowym. –

+0

Całkowicie opuściłem klasę będącą Bazą w tym momencie. Powinienem być po prostu T, ale widzę pełniejsze odpowiedzi, więc je zmienię. –

15

Gcc ostrzega Cię. Pomimo swoich wyglądów (wymaga to argumentu Base), nie jest szablonem funkcji.

Definicja klasy zawiera deklarację bez szablonu funkcji znajomego (bez szablonu), ale późniejsza definicja funkcji znajomego to szablon funkcji (tzn. Zaczyna się od szablonu ...).

Twój operator < < bierze podstawę *. To nie jest poprawne. Powinno być const & Baza zachować to wbudowany w semantyce

Pewnie patrzysz na coś jak poniżej:

template <typename T> 
class Base { 
    public: 
    friend ostream& operator << (ostream &out, Base<T> const &e){ 
     return out; 
    }; 
}; 

int main(){ 
    Base<int> b; 
    cout << b; 
} 

Jeśli chcesz w pełni na matrycy, to jest chyba to, co chcesz. Ale nie jestem pewien, ile jest to przydatne w porównaniu z poprzednim. Ponieważ wyszukiwanie obejmuje ADL, nigdy nie będziesz w stanie rozwiązać żadnego warunku, w którym T nie jest równe U (o ile wywołanie pochodzi z kontekstu niezwiązanego z tą klasą, np.z funkcji „main”)

template <typename T> 
class Base { 
    public: 
    template<class U> friend ostream& operator << (ostream &out, Base<U> const &e){ 
     return out; 
    }; 
}; 

int main(){ 
    Base<int> b; 
    cout << b; 
} 
+0

Cóż, użycie operatora '<<' nigdy nie znajdzie żadnej instancji z 'U! = T'. Może to jednak być bezpośrednie połączenie, które byłoby naprawdę dziwne. Ma to znaczenie tylko wtedy, gdy 'operator <<' dla 'Bazy ' uzyskał dostęp do zmiennej globalnej typu 'Base '. –

+0

@Ben Voigt: Dodano część "o ile połączenie pochodzi z kontekstu niezwiązanego z tą klasą, np. z funkcji "głównej". Mam nadzieję, że teraz jest wyraźniej – Chubsdad

+0

Może dodać, jak zdefiniować funkcję przyjaciela poza definicją klasy, dla kompletności? – Gauthier

10

Prawdopodobnie czego szukasz jest: tylko

template <typename T> 
class Base; 

template <typename T> 
ostream& operator<< (ostream &, const Base<T>&); 

template <typename T> 
class Base 
{ 
    public: 
    template<> 
    friend ostream& operator << <T>(ostream &, const Base<T> &); 
}; 

template <typename T> 
ostream& operator<< (ostream &out, const Base<T>& e) 
{ 
    return out << e->data; 
} 

to Przyjaciele pojedynczy instancji szablonu, ten, w którym parametr szablonu operatora dopasowuje parametr szablonu na klasę za .

AKTUALIZACJA: Niestety, jest to nielegalne. Zarówno MSVC, jak i Comeau odrzucają to. Co nasuwa pytanie, dlaczego oryginalny komunikat o błędzie sugerował DOKŁADNIE to podejście.

+6

[C++ FAQ] (http://www.parashift.com/c++-faq-lite/templates.html#faq-35.16) mówi, że wiersz 'friend' w deklaracji klasy powinien mieć' <> ', nie "". –

+2

I najwyraźniej nie powinieneś potrzebować linii 'template <>. (Brak dostępu do kompilatora już teraz, nie próbowałem go.) –

4

zmieniając

friend ostream& operator << (ostream& out, const Base<T>& e); 

do

friend ostream& operator << <T>(ostream& out, const Base<T>& e); 

powinny pracować, a także - po prostu rozwiązać identyczny problem w ten sposób.

0

zmieniając

friend ostream& operator << (ostream &out, Base<T> *e)` 

Aby

template<T> friend ostream& operator << (ostream &out, Base *e) 
Powiązane problemy