2010-10-25 39 views
11

Tengo algunos problemas para definir algunas sobrecargas de operador para las clases de plantilla. Tomemos esta clase hipotética, por ejemplo.Sobrecarga del operador en plantillas de clase

template <class T> 
class MyClass { 
    // ... 
}; 
  • operador + =

    // In MyClass.h 
    MyClass<T>& operator+=(const MyClass<T>& classObj); 
    
    
    // In MyClass.cpp 
    template <class T> 
    MyClass<T>& MyClass<T>::operator+=(const MyClass<T>& classObj) { 
        // ... 
        return *this; 
    } 
    

    Los resultados de este error del compilador:

    no match for 'operator+=' in 'classObj2 += classObj1' 
    
  • operador < <

    // In MyClass.h 
    friend std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj); 
    
    
    // In MyClass.cpp 
    template <class T> 
    std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj) { 
        // ... 
        return out; 
    } 
    

    Los resultados en esta advertencia del compilador:

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

¿qué estoy haciendo mal aquí?

+0

Se puede publicar algo de código real, que falla al compilar? – Naveen

+0

@Naveen: puede obtener una versión comprimida en http://www.box.net/shared/v23rj2f8e7 – Pieter

Respuesta

7
// In MyClass.h 
MyClass<T>& operator+=(const MyClass<T>& classObj); 


// In MyClass.cpp 
template <class T> 
MyClass<T>& MyClass<T>::operator+=(const MyClass<T>& classObj) { 
    // ... 
    return *this; 
} 

Esto es válido para las plantillas. El código fuente completo del operador debe estar en todas las unidades de traducción en las que se utiliza. Esto normalmente significa que el código está en línea en el encabezado.

Editar: Técnicamente, de acuerdo con la norma, es posible exportar plantillas, sin embargo muy pocos compiladores lo soportan. Además, también PUEDE hacer lo anterior si la plantilla está explícitamente instanciada en MyClass.cpp para todos los tipos que son T, pero en realidad, que normalmente desafía el punto de una plantilla.

Más edit: Leí su código y necesita algo de trabajo, por ejemplo, sobrecarga del operador []. Además, típicamente, haré que las dimensiones formen parte de los parámetros de la plantilla, permitiendo que la captura de + o + en el momento de la compilación no se realice y permita que el tipo se asigne de forma significativa. Su clase de excepción también debe derivar de std :: exception. Sin embargo, ninguno de ellos implica errores en tiempo de compilación, simplemente no son códigos geniales.

0

debe especificar que el amigo es una función de plantilla:

MyClass<T>& operator+=<>(const MyClass<T>& classObj); 

Ver this C++ FAQ Lite respuesta para obtener más detalles.

12

que tiene que decir lo siguiente (ya te haces amigo en su conjunto plantilla en lugar de sólo una especialización de la misma, en cuyo caso sólo se necesita añadir un <> después de la operator<<):

template<typename T> 
friend std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj); 

En realidad, no es necesario declararlo como amigo a menos que acceda a miembros privados o protegidos. Como acaba de recibir una advertencia , parece que su declaración de amistad no es una buena idea. Si solo desea declarar una especialización individual como amigo, puede hacerlo como se muestra a continuación, con una declaración de avance de la plantilla antes de su clase, para que operator<< se reconozca como una plantilla.

// before class definition ... 
template <class T> 
class MyClass; 

// note that this "T" is unrelated to the T of MyClass ! 
template<typename T> 
std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj); 

// in class definition ... 
friend std::ostream& operator<< <>(std::ostream& out, const MyClass<T>& classObj); 

Tanto lo anterior y de esta manera declaran especializaciones de él como amigos, pero la primera declara todos especializaciones como amigos, mientras que el segundo sólo declara la especialización de operator<< como un amigo cuya T es igual a la T de la clase que otorga amistad.

y en el otro caso, su declaración se ve bien, pero tenga en cuenta que no se puede += un MyClass<T> a un MyClass<U> cuando T y U son de tipo diferente con esa declaración (a menos que tenga una conversión implícita entre esos tipos). Usted puede hacer su += una plantilla miembro de

// In MyClass.h 
template<typename U> 
MyClass<T>& operator+=(const MyClass<U>& classObj); 


// In MyClass.cpp 
template <class T> template<typename U> 
MyClass<T>& MyClass<T>::operator+=(const MyClass<U>& classObj) { 
    // ... 
    return *this; 
} 
2

http://www.parashift.com/c++-faq-lite/template-friends.html

Esto me ayudó con el mismo problema.

Soln:

  1. declarar adelante la función amigo antes de la definición de la propia clase. Por ejemplo:

    template<typename T> class MyClass; // pre-declare the template class itself 
        template<typename T> std::ostream& operator<< (std::ostream& o, const MyClass <T>& x); 
    
  2. Declarar la función de su amigo en su clase con "<>" anexado al nombre de función.

    friend std::ostream& operator<< <> (std::ostream& o, const Foo<T>& x); 
    
+0

El enlace lleva al tiempo de espera. – TobiMcNamobi

-1

De esta manera funciona:

class A 
{ 
    struct Wrap 
    { 
     A& a; 
     Wrap(A& aa) aa(a) {} 
     operator int() { return a.value; } 
     operator std::string() { stringstream ss; ss << a.value; return ss.str(); } 
    } 
    Wrap operator*() { return Wrap(*this); } 
};