2010-02-08 8 views
5

Mientras trabajaba en algunos códigos gráficos hace un tiempo, escribí clases Rect y Region usando ints como el titular de coordenadas subyacente, y eso funcionó bien. La Región se implementó como una extensión de clase simple para una lista STL, y solo contiene una lista de Rectos.¿Cuál debería ser el tipo de iterador en esta plantilla de C++?

Ahora también necesito los mismos tipos de clases usando dobles como el titular de la coordenada subyacente, y decidí probar mi mano para templatarlo. Así que básicamente reemplacé "int" por "typename T" de una manera inteligente y solucioné los problemas.

Pero hay un problema restante que me ha dejado perplejo. Quiero calcular el cuadro delimitador de una Región haciendo una unión en todos los Rectos que lo componen. Eso funciona bien cuando no está templado, pero g ++ se ahoga en el iterador de la lista cuando esta está templada.

Aquí está el código correspondiente:

// Rect class that always remains normalized 
template <typename T> 
class KRect 
{ 
public: 

    // Ctors 
    KRect(void) 
     : _l(0), _t(0), _r(0), _b(0) 
    { 
    } 
    void unionRect(const KRect& r) 
    { 
     ... 
    } 

private: 
    T _l, _t, _r, _b; 
}; 

// Region class - this is very brain-dead 
template <typename T> 
class KRegion : public std::list< KRect<T> > 
{ 
public: 
    ... 

    // Accessors 
    KRect<T> boundingBox(void) 
    { 
     KRect<T> r; 
     iterator i; 
     for (i = this->begin(); i != this->end(); i++) 
     { 
      r.unionRect(*i); 
     } 
     return r; 
    } 
    ... 
}; 

Cuando ese código no es parte de una plantilla, así que T es definido (por ejemplo, un int), la línea "iterador i" funciona bien. Pero en lo que se ve arriba, g ++ en Ubuntu emite errores que no me parece muy informativo:

include/KGraphicsUtils.h: In member function ‘KRect<T> KRegion<T>::boundingBox()’: 
include/KGraphicsUtils.h:196: error: expected ‘;’ before ‘i’ 
include/KGraphicsUtils.h:197: error: ‘i’ was not declared in this scope 
include/KGraphicsUtils.h: In member function ‘KRect<T> KRegion<T>::boundingBox() [with T = int]’: 
--- redacted ---:111: instantiated from here 
include/KGraphicsUtils.h:196: error: dependent-name ‘std::foo::iterator’ is parsed as a non-type, but instantiation yields a type 
include/KGraphicsUtils.h:196: note: say ‘typename std::foo::iterator’ if a type is meant 

Mi conjetura es que este es un problema de la calificación de tipo y muchos efectos plantilla-y no estoy familiarizado. He intentado todo tipo de cosas como:

std::list< KRect<T> >::iterator i; 
this->iterator i; 

pero nada parece funcionar.

¿Alguna sugerencia?

+0

¿Qué compilador estás usando? Puedo compilarlo en VC++ 2010. – Jagannath

+0

Ya dijo g ++ - VC++ es tradicionalmente muy laxo con respecto a los nombres dependientes sin 'typename' o' template'. –

+0

Lo pasamos por alto. – Jagannath

Respuesta

9

iterator es un tipo dependiente (que depende de un parámetro de plantilla) y debe ser prefijado con typename:

typename std::list< KRect<T> >::iterator i; 

estilo mejor sería proporcionar una amplia clase typedef:

template <typename T> 
class KRegion : public std::list< KRect<T> > 
{ 
    typedef std::list< KRect<T> > base; 
    typedef typename base::iterator iterator; 
    // ... 
}; 
+0

¡Eso lo solucionó! ¡Gf, eres un caballero y un erudito! –

3

Creo que gf has your answer, pero me gustaría sugerir que la región administre una lista como miembro en lugar de una clase base:

template <typename T> 
class KRegion 
{ 
protected: 
    typedef std::list< KRect<T> > ListType; 
    ListType list; 
public: 
    ... 
    // Accessors 
    void addRect(KRect<T> & rect) { list->push_back(rect); } 
    ... 
    KRect<T> boundingBox(void) 
    { 
     KRect<T> r; 
     ListType::iterator i; 
     for (i = list->begin(); i != list->end(); i++) 
     { 
      r.unionRect(*i); 
     } 
     return r; 
    } 
    ... 
}; 

Mi motivación para esta sugerencia es que, un día, puede querer usar un contenedor diferente para almacenar sus KRects, y tener la lista como miembro interno le permitiría hacerlo sin romper todo su código de cliente.

+0

e.James, ¡también eres un caballero y un erudito! Es una gran idea; sin embargo, en este momento quiero que los clientes tengan acceso directo a los miembros de la lista porque soy demasiado flojo para escribir todos los accesadores. :-) –

+0

Eso es completamente justo ':)' Todos hemos estado allí. –

+0

Solo espero que ningún cliente escriba 'ListType * l = new KRegion (); borrar l; '... –

Cuestiones relacionadas