2009-08-19 27 views
27

Estoy tratando de sobrecargar el operador < < como amigo a una clase de plantilla par, pero me siguen dando una advertencia del compilador diciendooperador amigo << La sobrecarga de clase de plantilla

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

para este código:

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

da una segunda advertencia como una recomendación diciendo

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

Aquí es la definición de la función

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

y aquí está toda la clase.

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

No estaba seguro de qué sacar de la advertencia de recomendación, aparte de que tal vez tengo que ponerlo en algún lugar de la declaración de amigo. ¿Alguien sabe la sintaxis adecuada para esto? Gracias.

Respuesta

19

se declara operador < < como devolver un ostream &, pero no existe una instrucción de retorno en absoluto en el método. En caso de ser:

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

Aparte de eso, no tengo problemas o advertencias de compilar el código en Visual Studio 2008 con advertencias en el nivel 4. Oh, no son los clásicos errores de enlace, pero que es fácilmente pasado moviendo el definición de función de plantilla a la declaración de clase, como se explica en el C++ FAQ.

Mi código de prueba:

#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

Quiere hacer que una sola instancia (llamada "especialización" en términos genéricos) de esa plantilla sea un amigo. Lo hace de la siguiente manera

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

Debido a que el compilador sabe a partir de la lista de parámetros que los argumentos de plantilla son T y U, que no tienen que poner las que existen entre <...>, por lo que se pueden dejar vacíos. Tenga en cuenta que usted tiene que poner una declaración de operator<< por encima de la plantilla Pair, como la siguiente:

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 Esto es en realidad lo que el compilador se queja. La otra respuesta trata el problema con una solución temporal: en lugar de decirle al compilador que el amigo es la especialización de la plantilla, crea una función << de operador sin plantilla para los tipos dados. –

+0

Estoy de acuerdo con David; esta es la mejor solución en términos de mejores prácticas y buena programación. – Andry

+1

¡Guau, el ''> extra es fácil de perder! – Nick

1

simple versión en línea:

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

Versión revisada plantilla:

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>&); 
}; 
Cuestiones relacionadas