2010-10-28 13 views
37

Tengo una clase base similar al código siguiente. Estoy intentando sobrecargar < < para usar con cout. Sin embargo, g ++ está diciendo:declaración de amigo declara una función sin plantilla

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 

He intentado añadir <> después < < en la declaración de clase/prototipo. Sin embargo, entonces lo entiendo does not match any template declaration. He estado tratando de tener la definición del operador totalmente personalizada (lo que quiero), pero solo he podido hacer que funcione con el siguiente código, con el operador instanciado manualmente.

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; 
} 

quiero ir a tomar tal o similar en la cabecera, 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; 
} 

tengo leer en otro lugar en línea que poniendo <> entre < < y() en el prototipo debería arregla esto, pero no es así. ¿Puedo obtener esto en una plantilla de función única?

+4

eso es exactamente el problema resuelto por Dan Saks' [ "hacer nuevos amigos" modismo] (http://en.wikibooks.org/wiki/More_C % 2B% 2B_Idioms/Making_New_Friends). _ (Perdón por el último comentario.) _ –

Respuesta

29

Suena como que desea cambiar:

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

Para:

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

Así que no te creí, pero esto funciona. Sin embargo, no puedo usar 'T' porque' sombrea' la 'T' ya existente de la plantilla de la clase. –

+1

¿GCC le da una advertencia sobre el sombreado? –

+5

Sí, GCC dio una advertencia sobre el sombreado. Reemplacé T con Y y eso lo resolvió. 'error: sombras plantilla parm 'clase T'' –

-3

cambio

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

a

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

Definitivamente esto no funcionará. Además de dar 'employee.cpp: 32: error: 'T' no fue declarado en este alcance', incluso después de convertirlo en una plantilla en un archivo .h o .cpp, no funcionará debido a símbolos indefinidos durante el enlace. Además, sigo recibiendo la advertencia. Quiero que sea como una plantilla normal definida en un archivo de encabezado. –

+0

Eché de menos completamente que la clase era Base en ese punto. Debería ser T, pero veo respuestas más completas, así que las modifico. –

15

Gcc te advierte con razón. A pesar de sus apariencias (toma el argumento Base), no es una plantilla de función.

La definición de su clase tiene una declaración de plantilla de la función amiga (sin la plantilla), pero la definición de función amiga más tarde es una plantilla de función (es decir, comienza con la plantilla ...).

También su operador < < toma una Base *. Esto no es correcto. Debe ser const & Base de retener es incorporada en la semántica

Probablemente usted está viendo algo de la siguiente manera:

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

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

Si desea plenamente con plantilla, entonces esto es probablemente lo que quiere. Pero no estoy seguro de cuán útil es esto con respecto al anterior. Como la búsqueda implica ADL, nunca podrá resolver ninguna condición en la que T no sea igual a U (siempre que la llamada provenga de un contexto no relacionado con esta clase, p.desde la función 'principal')

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

Bueno, el uso del operador '<<' nunca encontraría ninguna instancia con 'U! = T'. Sin embargo, una llamada directa podría ser potencialmente, lo cual sería realmente extraño. Solo importaría si 'operator <<' for 'Base ' accede a una variable global de tipo 'Base '. –

+0

@Ben Voigt: Se agregó la parte 'siempre que la llamada provenga de un contexto no relacionado con esta clase, p. de la "función principal". Espero que esté más claro ahora – Chubsdad

+0

¿Tal vez añadir cómo definir la función de amigo fuera de la definición de clase, para completar? – Gauthier

10

Probablemente lo que busca es:

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; 
} 

Este amigos sólo una única instancia de la plantilla, aquel en el parámetro de plantilla del operador coincide parámetro de plantilla de la clase .

ACTUALIZACIÓN: Desafortunadamente, es ilegal. Tanto MSVC como Comeau lo rechazan. Lo que plantea la pregunta de por qué el mensaje de error original sugiere bastante EXACTAMENTE este enfoque.

+6

Las [Preguntas frecuentes de C++] (http://www.parashift.com/c++faq-lite/templates.html#faq-35.16) dice que la línea 'friend' en la declaración de clase debe tener un' <> ', no es un ''. –

+2

Y aparentemente no se supone que necesites la línea 'template <>' antes. (No hay acceso al compilador en este momento, no lo he probado). –

4

cambiar

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

a

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

debería funcionar tan bien - Acabo de resolver un problema idéntico de esta manera.

0

cambiar

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

Para

template<T> friend ostream& operator << (ostream &out, Base *e) 
Cuestiones relacionadas