[C con Clase] Templates y friend functions
Steven Davidson
srd4121 en njit.edu
Mie Mar 25 19:02:00 CET 2009
Hola Vicente,
vicente lozano wrote:
> Hola,
>
> Estaba practicando con los templates y queria hacer un template
> "variable", que pudiera representar a todos los tipos de variables y
> sobrecargar las operaciones con el mismo significado que tienen,
> como ejercicio academico.
>
> template <class T>
> class Var
> {
> T _val;
> public:
> Var(T v=0): _val(v) {}
> T getVar() const;
> ...
> template <class T>
> friend Var operator+(const Var v, const double);
> .....
> }
>
> inline T Var<T>::getVar() const { return _val;}
> ....
> template <class T>
> Var operator+(const Var v, const double d)
> {
> Var<T> res( (T) ( (double)v.getVar() + d) );
> return res;
> }
> ....
>
> Si pongo la linea subrayada me dice declaration of class T shadows
> template param class T.
> Si no la pongo me dice Friend declaration Var<T> operator+(const
> Var<T>&,double) declares a non-template function
>
> Seguro que tiene mas errores porque yo con lo de los templates aun
> estoy muy verde, conceptualmente los entiendo pero la sintaxis me
> pierde.
>
Veamos. Escribes:
template <class T>
friend Var operator+( const Var v, const double );
En primer lugar, como dije en un correo-e anterior, deberías pasar
objetos constantes por referencia: 'const Var &'.
Aquí, este operador es una plantilla, pero en este caso, la sobrecarga
depende de 'Var<T>'. Como ya estamos dentro de una clase-plantilla, no
hace falta redefinir T, que es el error que te indica el compilador, ni
tampoco ningún otro parámetro genérico. Al final, obtendremos,
template< typename T >
class Var
{
...
friend Var<T> operator+<T>( const Var<T> &v, const double );
};
También tienes un error en la implementación de la sobrecarga del
operador +. Escribes:
template <class T>
Var operator+( const Var v, const double d )
{
Var<T> res( (T) ( (double)v.getVar() + d) );
return res;
}
Debes indicar que la clase 'Var' no es una clase sino una plantilla.
Deberías escribir:
template< typename T >
Var<T> operator+( const Var<T> &v, const double d )
{
return Var<T>( (T) ( (double)v.getVar() + d) );
}
Sinceramente, estás forzando 'v' a ser 'double'. No veo que esto sea
apropiado según la intención que tienes. Sugiero hacer lo siguiente:
template< typename T >
Var<T> operator+( const Var<T> &var, const T &val )
{
return Var<T>( var.getVar() + val );
}
De todas maneras, creo que es mejor definir cada especialización según
el tipo fundamental que quieras pasar como parámetro a la plantilla. Por
ejemplo,
template<>
class Var<double>
{
private:
double _val;
public:
Var( double v=0 ) : _val(v) {}
double getVar() const;
...
friend Var<double> operator+<double>( const Var<double> &v, const
double d );
};
template<>
Var<double> operator+<double>( const Var<double> &var, const double &val )
{
return Var<double>( var.getVar() + val );
}
De esta forma, especializamos la definición de 'Var<double>' en lugar de
usar la definición genérica de 'Var<>'. En el caso de los tipos
fundamentales, aconsejaría que usaras 'long double' ya que es el "mayor"
tipo que existe de entre los tipos fundamentales. Cualquier tipo
fundamental puede ser promocionado a 'long double'.
Espero haber aclarado las dudas.
Steven
Más información sobre la lista de distribución Cconclase