Foros del Web » Programación para mayores de 30 ;) » C/C++ »

comparar dos tipos de datos y crear uno nuevo eligiendo el mayor

Estas en el tema de comparar dos tipos de datos y crear uno nuevo eligiendo el mayor en el foro de C/C++ en Foros del Web. Querría preguntar sobre cómo poder comparar dos tipos de datos, devolver un indicador con el mayor y crear un nuevo dato con el tipo de ...
  #1 (permalink)  
Antiguo 14/10/2014, 12:58
 
Fecha de Ingreso: octubre-2014
Mensajes: 23
Antigüedad: 9 años, 6 meses
Puntos: 0
Pregunta comparar dos tipos de datos y crear uno nuevo eligiendo el mayor

Querría preguntar sobre cómo poder comparar dos tipos de datos, devolver un indicador con el mayor y crear un nuevo dato con el tipo de dato elegido. Por ejemplo, para sumar C++ crea un dato nuevo con el tipo del numerador más completo.
Mi duda sería como hacerlo. He hecho ya mi propio código que compara dos tipos de datos, lo que me falla es a la hora de crear el nuevo dato, me dice que hay declaraciones en conflicto:
Código C++:
Ver original
  1. template<class T>
  2. template<typename T_1, typename T_2>
  3. Matrix<T_2> Matrix<T>::operator + (const Matrix<T_1> &m_2)
  4. {
  5.     T c;
  6.     T_1 b;
  7.     char a=compare(b,c);
  8.     switch(a)
  9.     {
  10.         case 's':
  11.             Matrix<short> result(I, J);
  12.             break;
  13.         case 't':
  14.             Matrix<unsigned short> result(I, J); // declaración en conflicto
  15.             break;
  16.         case 'i':
  17.             Matrix<int> result(I, J);
  18.             break;
  19.         case 'j':
  20.             Matrix<unsigned int> result(I, J);
  21.             break;
  22.         case 'l':
  23.             Matrix<long> result(I, J);
  24.             break;
  25.         case 'm':
  26.             Matrix<unsigned long> result(I, J);
  27.             break;
  28.         case 'x':
  29.             Matrix<long long> result(I, J);
  30.             break;
  31.         case 'y':
  32.             Matrix<unsigned long long> result(I, J);
  33.             break;
  34.         case 'f':
  35.             Matrix<float> result(I, J);
  36.             break;
  37.         case 'd':
  38.             Matrix<double> result(I, J);
  39.             break;
  40.         case 'e':
  41.             Matrix<long double> result(I, J);
  42.             break;
  43.     }
  44.     for(int i=0; i<I; i++)
  45.     {
  46.         for(int j=0; j<J; j++)
  47.         {
  48.             result.value(i,j)=this->value(i,j)+m_2.value(i,j);
  49.         }
  50.     }
  51.     return result;
  52. }
Adjunto las funciones de compare por si les queréis echar un vistazo.
Código C++:
Ver original
  1. template<typename D_1, typename D_2>
  2. char compare(D_1 a, D_2 b)
  3. {
  4.     return is_data(fmax(range(typeid(a).name()), range(typeid(b).name())));
  5. }r
  6.  
  7. char is_data(int a)
  8. {
  9.     char data;
  10.     switch(a)
  11.     {
  12.         case 1:
  13.             data='s';
  14.             break;
  15.         case 2:
  16.             data='t';
  17.             break;
  18.         case 3:
  19.             data='i';
  20.             break;
  21.         case 4:
  22.             data='j';
  23.             break;
  24.         case 5:
  25.             data='l';
  26.             break;
  27.         case 6:
  28.             data='m';
  29.             break;
  30.         case 7:
  31.             data='x';
  32.             break;
  33.         case 8:
  34.             data='y';
  35.             break;
  36.         case 9:
  37.             data='f';
  38.             break;
  39.         case 10:
  40.             data='d';
  41.             break;
  42.         case 11:
  43.             data='e';
  44.             break;
  45.     }
  46.     return data;
  47. }
  48.  
  49.  
  50. int range(const char *name)
  51. {
  52.     int range;
  53.     switch(*name)
  54.     {
  55.         case 's':
  56.             range=1;
  57.             break;
  58.         case 't':
  59.             range=2;
  60.             break;
  61.         case 'i':
  62.             range=3;
  63.             break;
  64.         case 'j':
  65.             range=4;
  66.             break;
  67.         case 'l':
  68.             range=5;
  69.             break;
  70.         case 'm':
  71.             range=6;
  72.             break;
  73.         case 'x':
  74.             range=7;
  75.             break;
  76.         case 'y':
  77.             range=8;
  78.             break;
  79.         case 'f':
  80.             range=9;
  81.             break;
  82.         case 'd':
  83.             range=10;
  84.             break;
  85.         case 'e':
  86.             range=11;
  87.             break;
  88.     }
  89.     return range;
  90. }

Supongo que existirá alguna manera que desconozco de simplificar el código.
Gracias.
  #2 (permalink)  
Antiguo 14/10/2014, 18:53
lareto
Invitado
 
Mensajes: n/a
Puntos:
Respuesta: comparar dos tipos de datos y crear uno nuevo eligiendo el mayor

No creo que se pueda hacer de esa manera. La idea de un template es que el compilador escriba el código de las clases y funciones template que necesita, ahorrándonos tener que escribirlas a mano, pero las reglas del juego siguen siendo las mismas. Por ejemplo, si has declarado que una función devuelve un cierto tipo de dato, no se puede cambiar eso en tiempo de ejecución. Con la idea de polimorfismo se puede decidir qué función o qué tipo de objeto (dentro de una familia) va a invocarse o crearse, pero esa función o tipo de objeto tienes que estar definidas desde antes.

Por otro lado, typeid devuelve un objeto que puede compararse con otro typeid, pero no hay ninguna garantía que dos llamadas consecutivas vayan a devolver la misma representación de ese objeto, y mucho menos que name() vaya a devolver lo que estás esperando. El estándar C++ sólo exige que los objetos devueltos sean comparables y que su comparación devuelva true o false, nada más; cualquier otra suposición será cierta o no dependiendo del compilador que se use. Así que ese mecanismo de comparar lo que devuelve name() mejor olvidarlo, a no ser que tengas garantías de que jamás se va a compilar con otro compilador y que jamás vaya a cambiarse de versión... bueno, olvídalo.

Pero bueno, entiendo que de todos modos estaría muy bien tener una respuesta (tu objeto Matrix suma de dos Matrixes) del tipo más comprensivo (estaba por poner "abarcativo", ¡dioses!), evitando que algún valor se trunquen eventualmente.

A ver qué te parece...

Si puedes compilar con C++11, se me ocurre un sucio hack echando mano de "auto" y de "decltype". auto es el tipo de una variable que el compilador deduce del entorno, y decltype devuelve el tipo de la variable de su argumento.

1) Entonces, se podría dejar que el compilador resuelva las promociones entre los tipos de datos, como lo hace siempre, por ejemplo:
short + int = int, etcétera.

2)
Código C++:
Ver original
  1. auto type = (data_1) 1 + (data_2) 2;
si data_1 fuera un int y data_2 un double, "auto" sería un doble.

3)
Código C++:
Ver original
  1. decltype(type) c[a][b]={{0,0},{2,7},{0,0},{4,9},{0,0}};
estaría declarando tu matriz de tipo double, siguiendo el ejemplo.

4) y de la misma manera, poniendo decltype(type) en donde necesites definir el tipo, por ejemplo también en
Código C++:
Ver original
  1. Matrix<decltype(type)> M(a, b);

Así tendrías las promociones definidas al crear los objetos de tipo Matrix, y las sumas de sus elementos también ya serían del mismo tipo.

Lareto :)
  #3 (permalink)  
Antiguo 15/10/2014, 04:09
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 7 meses
Puntos: 204
Respuesta: comparar dos tipos de datos y crear uno nuevo eligiendo el mayor

Cita:
Iniciado por alexpglez98 Ver Mensaje
Mi duda sería como hacerlo. He hecho ya mi propio código que compara dos tipos de datos, lo que me falla es a la hora de crear el nuevo dato, me dice que hay declaraciones en conflicto:
Te da conflicto porque las variables que declaras dentro de los case tienen todas, por decirlo de alguna forma, el mismo ámbito y colisionan entre ellas. Puedes evitar el problema simplemente poniendo el contenido de los case entre llaves:

Código C++:
Ver original
  1. case 's':
  2. {
  3.   Matrix<short> result(I, J);
  4.   break;
  5. }
  6.  
  7. case 't':
  8. {
  9.   Matrix<unsigned short> result(I, J); // declaración en conflicto
  10.   break;
  11. }

En cualquier caso has de saber que los objetos que estás creando dentro del switch se eliminan al salir de dicho switch, por lo que el if que tienes después te va a dar error porque no va a encontrar una variable que se llamen "result".

Por otro lado, tienes que tener en cuenta que los templates son tratados de forma especial por el compilador. En tiempo de compilación el compilador chequea los diferentes usos de los templates y crea una versión específica para cada uso. Esto quiere decir que un programa compilado no tiene templates sino funciones y clases sobrecargadas (todas las especializaciones que se usen en el programa).

El rollo que te he contado implica que el tipo de retorno, "Matrix<T_2>" va a tener que estar determinado en el momento de llamar a la función y su repercusión más inmediata es que no vas a poder retornar dentro de la misma especialización un Matrix<int> y un Matrix<char> porque son tipos diferentes... y no puedes elegir al gusto el tipo a retornar dentro de la función porque la elección hay que hacerla bastante antes.

Dicho de otra forma, "result" tiene que estar declarado forzosamente tal que:

Código C++:
Ver original
  1. template<class T>
  2. template<typename T_1, typename T_2>
  3. Matrix<T_2> Matrix<T>::operator + (const Matrix<T_1> &m_2)
  4. {
  5.   Matrix<T_2> result( I, J );
  6.  
  7.   // ...
  8.  
  9.   return result;
  10. }

Los tipos de I y J no aparecen en tu código. Si son variables globales te aconsejo evitar su uso. Si son constantes (en C++ te aconsejo usar static const en vez de define para declarar constantes) entonces olvida lo que te he dicho.

Por otro lado, y ya para terminar, el bucle que calcula la suma de las dos matrices anteriores puede que necesite una pequeña ayuda con las conversiones de datos para evitar warnings durante la compilación... quizás algo del tipo:

Código C++:
Ver original
  1. for(int i=0; i<I; i++)
  2. {
  3.     for(int j=0; j<J; j++)
  4.     {
  5.         result.value(i,j) = static_cast<T_2>( this->value(i,j) ) + static_cast<T_2>( m_2.value(i,j) );
  6.     }
  7. }

Un saludo.
  #4 (permalink)  
Antiguo 15/10/2014, 14:02
 
Fecha de Ingreso: octubre-2014
Mensajes: 23
Antigüedad: 9 años, 6 meses
Puntos: 0
Respuesta: comparar dos tipos de datos y crear uno nuevo eligiendo el mayor

Lareto, entiendo lo que dices. Aunque no se como aplicarlo muy bien, igual tendría que hacer una función intermediaria para poderlo implementar..
I y J son variables de la clase, asi que supongo que no hay problema en ponerlo asi. Lo de las constantes no lo estoy teniendo muy en cuenta, el caso es que no acabo de haber entendido el const del todo. Lo tendré en cuenta por si tengo algún error futuro, gracias.

Yo creo que lo mejor sería devolver long double, aunque no aprovecha muy bien la memoria, pero después de la función el objeto long double se eliminaría y nos quedaríamos igual de bien.

Etiquetas: funcion, int, mayor
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 08:18.