2009-06-07 9 views
5

Hace poco estuve tratando de calibrar las capacidades de sobrecarga/plantilla de mi operador y como una pequeña prueba, creé la clase de Contenedor a continuación. Si bien este código se compila correctamente y funciona correctamente en MSVC 2008 (muestra 11), tanto MinGW/GCC como Comeau se bloquean en la sobrecarga operator+. Como confío en ellos más que en MSVC, estoy tratando de descubrir qué estoy haciendo mal.Sobrecarga del operador binario en una clase de plantilla

Aquí está el código:

#include <iostream> 

using namespace std; 

template <typename T> 
class Container 
{ 
     friend Container<T> operator+ <> (Container<T>& lhs, Container<T>& rhs); 
    public: void setobj(T ob); 
    T getobj(); 
     private: T obj; 
}; 

template <typename T> 
void Container<T>::setobj(T ob) 
{ 
    obj = ob; 
} 

template <typename T> 
T Container<T>::getobj() 
{ 
    return obj; 
} 

template <typename T> 
Container<T> operator+ <> (Container<T>& lhs, Container<T>& rhs) 
{ 
     Container<T> temp; 
     temp.obj = lhs.obj + rhs.obj; 
     return temp; 
} 

int main() 
{  
    Container<int> a, b; 

a.setobj(5); 
    b.setobj(6); 

Container<int> c = a + b; 

cout << c.getobj() << endl; 

    return 0; 
} 

Este es el error Comeau da:

Comeau C/C++ 4.3.10.1 (Oct 6 2008 11:28:09) for ONLINE_EVALUATION_BETA2 
Copyright 1988-2008 Comeau Computing. All rights reserved. 
MODE:strict errors C++ C++0x_extensions 

"ComeauTest.c", line 27: error: an explicit template argument list is not allowed 
      on this declaration 
    Container<T> operator+ <> (Container<T>& lhs, Container<T>& rhs) 
      ^

1 error detected in the compilation of "ComeauTest.c". 

estoy teniendo un tiempo difícil tratando de conseguir Comeau/MingGW a jugar a la pelota, así que de ahí Me dirijo a ustedes chicos. Ha pasado mucho tiempo desde que mi cerebro se ha derretido tanto bajo el peso de la sintaxis de C++, así que me siento un poco avergonzado;).

EDIT: Eliminado un error de lvalue (irrelevante) en el volcado inicial de Comeau.

Respuesta

5

Encontré la solución gracias to this forum posting. Esencialmente, debe tener un prototipo de función antes de poder usar "amigo" en él dentro de la clase, sin embargo, también necesita que se declare la clase para definir correctamente el prototipo de la función. Por lo tanto, la solución es tener dos prototipos de definiciones (de la función y la clase) en la parte superior. El código siguiente se compila en las tres compiladores:

#include <iostream> 

using namespace std; 

//added lines below 
template<typename T> class Container; 
template<typename T> Container<T> operator+ (Container<T>& lhs, Container<T>& rhs); 

template <typename T> 
class Container 
{ 
     friend Container<T> operator+ <> (Container<T>& lhs, Container<T>& rhs); 
     public: void setobj(T ob); 
       T getobj(); 
     private: T obj; 
}; 

template <typename T> 
void Container<T>::setobj(T ob) 
{ 
     obj = ob; 
} 

template <typename T> 
T Container<T>::getobj() 
{ 
     return obj; 
} 

template <typename T> 
Container<T> operator+ (Container<T>& lhs, Container<T>& rhs) 
{ 
     Container<T> temp; 
     temp.obj = lhs.obj + rhs.obj; 
     return temp; 
} 

int main() 
{  
    Container<int> a, b; 

    a.setobj(5); 
    b.setobj(6); 

    Container<int> c = a + b; 

    cout << c.getobj() << endl; 

    return 0; 
} 
2
template <typename T> 
Container<T> operator+ <> (Container<T>& lhs, Container<T>& rhs) 

Aquí el "<>" después operator+ debe eliminarse ya que apenas está declarando una nueva plantilla, no especializado una general. También al menos g++ quiere ver la declaración de plantilla antes de la declaración de amigo, por lo que debe moverse antes de la declaración de Container. Por lo que el siguiente orden de las declaraciones funciona:

// forward declaration of Container<T> 
template <typename T> 
class Container; 

template <typename T> 
Container<T> operator+(Container<T>& lhs, Container<T>& rhs) 
{ ... } 

template <typename T> 
class Container 
{ 
     friend Container<T> operator+ <> (Container<T>& lhs, Container<T>& rhs); 
     ... 
}; 
0

'operador +' no es una función miembro, y no es templated. Es solo el operador + el que toma los parámetros de las plantillas. '

template <typename T> 
Container<T> operator+ (Container<T>& lhs, Container<T>& rhs) 
+1

Creo que el operador + es una función de plantilla, ¿no es así? Un contenedor y un contenedor serán de dos tipos diferentes, por lo que el compilador necesitará generar dos operadores diferentes para tratarlos. ¿Eso no significa que operador + es una función de plantilla? –

+0

It * is * una plantilla de función. Pero está en lo cierto al omitir el "<>" de la definición de la plantilla. ("<>" solo se usa cuando se especifica una plantilla de función * para llamar *, y aun así solo es necesario cuando existe una función que no es de plantilla con el mismo nombre) –

1

He probado esto en GCC y lo he compilado y ejecutado con algunos cambios. Hubo dos cambios que tuve que hacer para hacer feliz a GCC.

Una fue la declaración de la función de plantilla de amigo. Es su propia declaración de plantilla separada de la clase uno, así que usé U en lugar de la clase Container 'T allí. También me deshice del <> después del operador +. No creo que los necesites a menos que estés escribiendo una especialización de plantilla.

 template<typename U> 
     friend Container<U> operator+ (Container<U>& lhs, Container<U>& rhs); 

Dos, la línea

no voló con GCC porque usted está pidiendo para almacenar una referencia a un temporal (el resultado de la suma). Quité el signo y para que haya un lugar donde almacenar el resultado.

Vi su publicación hace un momento, que también funciona debido a las declaraciones directas. Supongo que publicaré esto de todos modos como una alternativa que no los requiere. Por supuesto que solo probé en GCC ...

+0

Encontré esto en otra publicación en línea y este sería mi preferencia personal de los dos (más conciso). – GRB

+0

Este otorgará acceso a todas las especializaciones de plantilla (para que el operador + pueda acceder a las partes privadas del Contenedor ). El código del asker solo desea otorgar acceso al operador + (solo el operador + puede acceder a las partes privadas del contenedor ) –

+0

@litb: Vi mencionar ese problema también, pero tengo problemas para configurar ese escenario. ¿Podría proporcionar un fragmento de código de ejemplo donde la sobrecarga int acceda a los miembros privados de un flotador? – GRB

1

Será mejor que defina la función directamente en la clase. Además, debe pasar los parámetros como referencias const.

template <typename T> 
class Container 
{ 
public: 
    friend Container operator+ (Container const & lhs, Container const & rhs) 
    { 
     // ... 
    } 
};