Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: GisiNA en 7 Mayo 2017, 22:39 pm



Título: C++ Sobrecarga de un operador por medio de un template?
Publicado por: GisiNA en 7 Mayo 2017, 22:39 pm
Hola a todos!

Estoy tratando de aprender por mi misma los elementos básicos de C++.
He buscado en la web una respuesta a la siguiente duda, pero no la he hallado.

Quizás este problema no tiene solución.

Es posible traspasar un operador a un template de modo tal que el operador no solamente sea sobrecargado sino que a la vez sea reemplazado por otro, y de ese modo no sea necesario tener que repetir el mismo código solo por cambiar la operación, o sea, algo como esto:

Código
  1. Num operator +(const Num &p1,const Num &p2)
  2. {
  3.    Num erg;
  4. erg.a = p1.a + p2.a;
  5. erg.b = p1.b + p2.b;
  6.    return erg;
  7. }
  8.  
  9. Num operator *(const Num &p1,const Num &p2)
  10. {
  11.    Num erg;
  12. erg.a = p1.a * p2.a;
  13. erg.b = p1.b * p2.b;
  14.    return erg;
  15. }
  16.  
  17. Num operator -(const Num &p1,const Num &p2)
  18. {
  19.    Num erg;
  20. erg.a = p1.a - p2.a;
  21. erg.b = p1.b - p2.b;
  22.    return erg;
  23. }
  24.  
etc....

A continuación les dejo el código. Es uno sencillo del que muchos similares pueden encontrarse en libros y en la web:

Código
  1. #include <iostream>
  2.  
  3. using namespace std;
  4.  
  5. class Num
  6. {
  7. public:
  8.    double a, b;
  9. };
  10.  
  11. Num operator +(const Num &p1,const Num &p2)
  12. {
  13.    Num erg;
  14. erg.a = p1.a + p2.a;
  15. erg.b = p1.b + p2.b;
  16.    return erg;
  17. }
  18.  
  19. int main()
  20. {
  21.    Num num1;
  22. num1.a=1;
  23. num1.b=75;
  24.    Num num2;
  25. num2.a=150;
  26. num2.b=175;
  27.    Num num1und2 = num1 + num2;
  28.  
  29.    cout << "num1 " << "a: " << num1.a << ", b: " << num1.b << endl;
  30.    cout << "num2 " << "a: " << num2.a << ", b: " << num2.b << endl;
  31.    cout << "num1und2 " << "a: " << num1und2.a << ", b: " << num1und2.b << endl;
  32.  
  33.    return 0;
  34. }
  35.  

Ese código me gustaría poder reescribir más o menos como sigue, de modo que sea posible traspasar al templete el operador:

Código
  1. #include <iostream>
  2.  
  3. using namespace std;
  4.  
  5. class Num
  6. {
  7. public:
  8.    double a, b;
  9. };
  10.  
  11. template<operator op> // * Algo por este estilo
  12. Num operator op(const Num &p1,const Num &p2)
  13. {
  14.    Num erg;
  15. erg.a = p1.a op p2.a; // * Donde dice op que sea reemplazado por el operador deseado
  16. erg.b = p1.b op p2.b;   // * Donde dice op que sea reemplazado por el operador deseado
  17.    return erg;
  18. }
  19.  
  20. int main()
  21. {
  22.    Num num1;
  23. num1.a=1;
  24. num1.b=75;
  25.  
  26.    Num num2;
  27. num2.a=150;
  28. num2.b=175;
  29.  
  30.    Num num1und2 = num1 + num2; // * Modificando acá el operador que cambie arriba la operación
  31.  
  32.   cout << "num1und2 " << "a: " << num1und2.a << ", b: " << num1und2.b << endl;
  33.  
  34.    return 0;
  35. }
  36.  

Es posible realizar una hazaña de ese tipo?


Título: Re: C++ Sobrecarga de un operador por medio de un template?
Publicado por: MAFUS en 8 Mayo 2017, 01:04 am
Tienes hecha mal la sobrecarga.
A parte de eso puedes hacer uso de algo más primitivo que las plantillas: el preprocesador.

Un ejemplo de cómo hacerlo sería así:
Código
  1. #include <iostream>
  2.  
  3. using namespace std;
  4.  
  5. class Num
  6. {
  7. public:
  8.    double a, b;
  9.  
  10.    /* Dentro del mismo objeto, o en el archivo de implementación
  11.      * preparo una macro que contendrá el código al que solo deberé
  12.      * pasarle el operador que quiero. Pero cuidado pues el operador
  13.      * deberá ser compatible. Solo sirve para ahorrar código.
  14.      */
  15.  
  16.    #define SET_OP(op)                                                 \
  17.     Num operator op(const Num &p)                                      \
  18.     {                                                                  \
  19.         Num erg;                                                       \
  20.         erg.a = a op p.a;                                              \
  21.         erg.b = b op p.b;                                              \
  22.         return erg;                                                    \
  23.     }
  24.  
  25.    // Hora de usar la macro con cada uno de los operadores.
  26.  
  27.    SET_OP(+);
  28.    SET_OP(-);
  29.    SET_OP(*);
  30.    SET_OP(/);
  31.  
  32.    /* Elimino el símbolo de la macro por si quiero usarla más
  33.      * adelnate con otros operadores u otro tipo de dato.
  34.      */
  35.  
  36.    #undef SET_OP
  37. };
  38.  
  39. int main()
  40. {
  41.    Num num1;
  42. num1.a=1;
  43. num1.b=75;
  44.  
  45.    Num num2;
  46. num2.a=150;
  47. num2.b=175;
  48.  
  49.    Num num1und2 = num1 + num2; // * Modificando acá el operador que cambie arriba la operación
  50.  
  51.   cout << "num1und2 " << "a: " << num1und2.a << ", b: " << num1und2.b << endl;
  52.  
  53.    return 0;
  54. }


Título: Re: C++ Sobrecarga de un operador por medio de un template?
Publicado por: GisiNA en 8 Mayo 2017, 01:50 am
Hola!

Muchas gracias por tu respuesta!

Está muy bueno!  ;-)

Sin embargo, tengo el interés de saber si existe la posibilidad de hacer lo mismo sobrecargando operadores usando templates. Es un interés personal, pues, no he hallado una solución en la web ni en los libros de los que dispongo.

Quisiera saber si existe un método de esa manera, o si no es posible hacerlo de esa manera.
Mi segunda consulta va en relación al comentario

"Tienes hecha mal la sobrecarga."

Sobre qué base se levanta tu comentario?

Saludos!


Título: Re: C++ Sobrecarga de un operador por medio de un template?
Publicado por: MAFUS en 8 Mayo 2017, 02:16 am
Si miras los errores que lanza el compilador, para el código que tienes, dice:
cpp.cpp:10:47: error: ‘Num Num::operator+(const Num&, const Num&)’ must take either zero or one argument
     Num operator +(const Num &p1,const Num &p2)

Esta sobrecarga, dice el compilador, solo puede tener ningún o un solo argumento. A partir de aquí, una búsqueda rápida por internet te lleva al código correcto para estas sobrecargas.

De todas formas no creo que te deje hacer lo que quieres porqué las plantillas son para adaptar las variables y lo que buscas es adaptar el nombre de un método.


Título: Re: C++ Sobrecarga de un operador por medio de un template?
Publicado por: GisiNA en 8 Mayo 2017, 08:14 am
Bah... a mi me compila muy bien y arroja el resultado esperado.
No sabría decirte el porqué en tu caso no compila.

Ahora bien, de regreso a mi consulta..., sabes quizás si es posible realizar lo que describo?

Saludos!


Título: Re: C++ Sobrecarga de un operador por medio de un template?
Publicado por: MAFUS en 8 Mayo 2017, 09:32 am
No deben existir templates para operadores. El hecho es que una sobrecarga de operadores, a vistas de código intermedio, son funciones y no tipos de datos. Los templates existen para adaptar tipos de datos a funciones y hacerlas genéricas. Como tu idea es cambiar a qué función llamar según el operador que quieres pasar la única forma que se me ocurre es mediante el preprocesador.


Título: Re: C++ Sobrecarga de un operador por medio de un template?
Publicado por: GisiNA en 8 Mayo 2017, 13:09 pm
Ohhhh! Entiendo! Muy buena respuesta!
Gracias!!


Título: Re: C++ Sobrecarga de un operador por medio de un template?
Publicado por: CalgaryCorpus en 9 Mayo 2017, 06:18 am
Una solucion alternativa a usar macros, pero que tampoco es exactamente lo que buscas, es usar functors. Se trata de clases o structs que tienen un metodo operator() y que puede ser redefinido en otras clases. Es eso lo que hice en el codigo que incluyo aqui:


Código
  1. #include <functional>
  2. #include <iostream>
  3.  
  4. using namespace std;
  5.  
  6. // tu clase Num, con metodos adicionales para hacer mas corto el resto
  7. class Num
  8. {
  9. public:
  10.    double a, b;
  11.    Num(double x, double y) : a(x), b(y) {}
  12.    void show() { cout << a << ":" << b << endl; }
  13. };
  14.  
  15. // la definicion del functor
  16. struct Operador : public binary_function<Num,Num,Num> {
  17.    virtual Num operator()(Num&n1, Num& n2) = 0;
  18. };
  19.  
  20. // los operadores
  21. struct Sumador : public Operador {
  22.  Num operator() (Num& n1, Num& n2) {return Num(n1.a+n2.a,n1.b+n2.b);}
  23. } sumador;
  24.  
  25. struct Multiplicador : public Operador {
  26.  Num operator() (Num& n1, Num& n2) {return Num(n1.a*n2.a,n1.b*n2.b);}
  27. } multiplicador;
  28.  
  29. // definir otros, si se quiere ...
  30.  
  31. // una funcion que aplica los operadores
  32. Num apply_op(Num n1, Num n2, Operador& op) {
  33.  return op(n1, n2);
  34. }
  35.  
  36. int main() {
  37.    Num num1(1,2), num2(3,4);
  38.  
  39.    apply_op(num1, num2, sumador).show();
  40.    apply_op(num1, num2, multiplicador).show();
  41.  
  42.    // en vez de hacer .show(), como arriba, se puede asignar el resultado, si se quiere
  43.    Num resultado = apply_op( num1, num2, sumador );
  44.    resultado.show();
  45.  
  46.    return 0;
  47. }