Ver Mensaje Individual
  #11 (permalink)  
Antiguo 29/06/2016, 01:26
eferion
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 7 meses
Puntos: 204
Respuesta: Como declarar un tipo

Del código que has puesto yo veo los siguientes problemas:

Te falta un punto y coma después de t_arista:

Código C++:
Ver original
  1. typedef arista<datoarista_t,datonodo_t> t_arista
  2. struct TratarAristaConNiveles

Te falta cerrar una llave:

Código C++:
Ver original
  1. struct ImprimirArbol:public TratarAristaConNiveles
  2. {
  3.     ImprimirArbol(std::pair<pArista,int>par, std::list<pArista>&l):TratarAristaConNiveles(par,l){}
  4.     void operator()(std::pair<pArista,int>P)
  5.     {
  6.         std::cout<<P.second<<"-";
  7.         std::cout<<"|";
  8.         for (int i=0;i<P.second;i++)
  9.         {
  10.             std::cout<<"----";
  11.         }
  12.         std::cout<<">";
  13.     } // <<<---- ESTA!!!!
  14. ..................//aquí ya tengo otro tipo de error, pero no es el que me preocupa ahora
  15. };

Y con eso a mí ya me compila.

Ahora una pequeña labor de refactorización:

El código de functores.h no necesita conocer la clase grafo sino únicamente a arista y nodo. Parece lógico entonces mover estas dos clases a un fichero independiente para que functores.h no tenga que incluir grafo.h. También puedes eliminar las declaration forward de arista y nodo que tienes en functores.h.

arista.h
Código C++:
Ver original
  1. #ifndef ARISTA_H
  2. #define ARISTA_H
  3.  
  4. template <typename,typename>
  5. struct nodo;
  6.  
  7. template <typename DATOA, typename DATON>
  8. struct arista
  9. {
  10.   DATOA datoarista;
  11.   nodo<DATON,DATOA>* destino;
  12.   arista<DATOA,DATON>* siguiente;
  13.   arista<DATOA,DATON>* anterior;
  14.  
  15.   // ...
  16. };
  17.  
  18. #endif // ARISTA_H

nodo.h
Código C++:
Ver original
  1. #ifndef NODO_H
  2. #define NODO_H
  3.  
  4. template<typename, typename>
  5. struct arista;
  6.  
  7. template <typename DATON, typename DATOA>
  8. struct nodo
  9. {
  10.   DATON datonodo;
  11.   unsigned short int nPadres;
  12.   nodo<DATON,DATOA>* siguiente;
  13.   arista<DATOA,DATON>* adyacente;
  14.  
  15.   // ...
  16. };
  17.  
  18. #endif // NODO_H
Por otro lado no veo nada en functores.h que impida convertir las clases en templates para no tener que crear especializaciones en ese punto:

Código C++:
Ver original
  1. #ifndef FUNCTORES_H
  2. #define FUNCTORES_H
  3.  
  4. #include <iomanip>
  5.  
  6. #include "arista.h"
  7. #include "nodo.h"
  8.  
  9. template<class DATOA, class DATON>
  10. struct TratarAristaConNiveles
  11. {
  12.     typedef nodo<DATON,DATOA>* pNodo;
  13.     typedef arista<DATOA,DATON>* pArista;
  14.    
  15.     //typedef arista<MedCert,Concepto>* pArista;
  16.     std::pair<pArista,int>pareja;
  17.     std::list<pArista> &listaAristasConMediciones;
  18.     TratarAristaConNiveles(std::pair<pArista,int>par, std::list<pArista>&l):pareja(par),listaAristasConMediciones(l){}
  19.  
  20.     virtual void operator()(std::pair<pArista,int>P)=0;
  21. };
  22.  
  23. template<class DATOA, class DATON>
  24. struct ImprimirArbol
  25.   : public TratarAristaConNiveles<DATOA,DATON>
  26. {
  27.   // ...
  28. };

El código anterior no compilará porque un template no puede definir una función virtual pura. Hay dos posibles formas de solucionarlo: más herencia o darle una implementación básica a dicha función. Yo personalmente prefiero la primera, pero no es implementable porque la firma del operador función es dependiente de los tipos del template así que solo nos queda la segunda opción:

Código C++:
Ver original
  1. template<class DATOA, class DATON>
  2. struct TratarAristaConNiveles
  3. {
  4.     typedef nodo<DATON,DATOA>* pNodo;
  5.     typedef arista<DATOA,DATON>* pArista;
  6.    
  7.     //typedef arista<MedCert,Concepto>* pArista;
  8.     std::pair<pArista,int>pareja;
  9.     std::list<pArista> &listaAristasConMediciones;
  10.     TratarAristaConNiveles(std::pair<pArista,int>par, std::list<pArista>&l):pareja(par),listaAristasConMediciones(l){}
  11.  
  12.     virtual void operator()(std::pair<pArista,int>P)
  13.     {}
  14. };

Ahora el problema que tenemos es que la clase hija no va a reconocer las declaraciones de pNodo y pArista declaradas en TratarAristaConNiveles. Este error tiene que ver con la forma en la que se tratan los templates en C++.

La forma más sencilla de lidiar con este problema, desde mi punto de vista, pasa por declarar una función traits que declare por sí misma los tipos pArista y pNodo para no tener que redeclararlos cada dos por tres:

Código C++:
Ver original
  1. template<class,class>
  2. struct arista;
  3.  
  4. template<class,class>
  5. struct nodo;
  6.  
  7. template<class DATOA, class DATON>
  8. struct traits
  9. {
  10.   typedef arista<DATOA,DATON>* pArista;
  11.   typedef nodo<DATON,DATOA>* pNodo;
  12. };

Y se usa así:

Código C++:
Ver original
  1. template<class DATOA, class DATON>
  2. struct TratarAristaConNiveles
  3. {
  4.   typedef traits<DATOA,DATON> myTraits;
  5.   typedef typename myTraits::pNodo pNodo;
  6.   typedef typename myTraits::pArista pArista;
  7.  
  8.   //typedef arista<MedCert,Concepto>* pArista;
  9.   std::pair<pArista,int>pareja;
  10.   std::list<pArista> &listaAristasConMediciones;
  11.   TratarAristaConNiveles(std::pair<pArista,int>par,
  12.                          std::list<pArista>&l)
  13.     : pareja(par),
  14.       listaAristasConMediciones(l)
  15.   { }
  16.  
  17.   virtual void operator()(std::pair<pArista,int>P)=0;
  18. };
  19.  
  20. template<class DATOA, class DATON>
  21. struct ImprimirArbol
  22.   : TratarAristaConNiveles<DATOA,DATON>
  23. {
  24.   typedef typename TratarAristaConNiveles<DATOA,DATON>::myTraits myTraits;
  25.   typedef typename myTraits::pNodo pNodo;
  26.   typedef typename myTraits::pArista pArista;
  27.  
  28.   ImprimirArbol(std::pair<pArista,int>par,
  29.                 std::list<pArista>&l)
  30.     : TratarAristaConNiveles<DATOA,DATON>(par,l)
  31.   { }
  32. };

o así (si te quieres ahorrar un alias):

Código C++:
Ver original
  1. template <typename DATOA, typename DATON>
  2. struct arista
  3. {
  4.     typedef typename traits<DATOA,DATON>::pArista pArista;
  5.     typedef typename traits<DATOA,DATON>::pNodo pNodo;
  6.  
  7.     DATOA datoarista;
  8.     pNodo destino;
  9.     pArista siguiente;
  10.     pArista anterior;
  11. };

typename hay que ponerlo porque el tipo del que intentamos crear el alias es dependiente de un template... cosas del lenguaje.

Con C++11 quedaría algo más elegante, desde mi punto de vista:

Código C++:
Ver original
  1. struct TratarAristaConNiveles
  2. {
  3.   using myTraits = traits<DATOA,DATON>;
  4.   using pNodo    = typename myTraits::pNodo;
  5.   using pArista  = typename myTraits::pArista;
  6. };
  7.  
  8. template<class DATOA, class DATON>
  9. struct ImprimirArbol
  10.   : TratarAristaConNiveles<DATOA,DATON>
  11. {
  12.   using myTraits = typename TratarAristaConNiveles<DATOA,DATON>::myTraits;
  13.   using pNodo    = typename myTraits::pNodo;
  14.   using pArista  = typename myTraits::pArista;
  15. };

La ventaja de usar la clase traits es que podemos arrastrar esas definiciones a donde nos plazca de forma algo más sencilla que hacerlo a mano, donde tienes que recordar el orden de DATOA y DATON en cada declaración de nodo y arista.

Para rematar, dado que ahora tenemos templates nuevos, hay que actualizar el archivo grafo.h. Ahí podemos eliminar las declaration forward de TratarAristaConNiveles e ImprimirArbol, además de actualizar la firma de algunas funciones:

Código C++:
Ver original
  1. void recorrerGrafoConNiveles(pNodo& inicio,
  2.                              TratarAristaConNiveles<DATOA,DATON>& tratamiento,
  3.                              int n=0);

Y creo que como primer paso es suficiente. Seguir refactorizando ese código lleva su tiempo sobretodo para comprenderlo (paso imprescindible para que el nuevo código funcione correctamente jejeje), pero con estos cambios al menos es compilable.

Yo empezaría por meter la clase traits en grafo para tener una declaración unificada de los tipos pArista y pNodo.

Un saludo.
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.

Última edición por eferion; 29/06/2016 a las 02:12