2010-02-08 16 views
5

Mentre lavoravo su qualche codice grafico qualche tempo fa, ho scritto le classi Rect e Region usando gli interi come il coordinatore sottostante, e questo ha funzionato bene. La Regione è stata implementata come semplice estensione di classe in un elenco STL e contiene solo un elenco di Rects.Quale dovrebbe essere il tipo iteratore in questo modello C++?

Ora ho anche bisogno dello stesso tipo di classi che usano il doppio come il coordinatore sottostante, e ho deciso di provare a templatizzarlo. Quindi ho praticamente sostituito "int" con "typename T" in modo intelligente e risolto i problemi.

Ma c'è ancora un problema che mi ha bloccato. Voglio calcolare il riquadro di delimitazione di una regione eseguendo un'unione su tutti i Rects che lo compongono. Funziona bene quando non è templatizzato, ma g ++ si strozza sull'elenco iteratore quando questo è templatizzato.

Ecco il codice rilevante:

// 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; 
    } 
    ... 
}; 

Quando questo codice non è parte di un modello, in modo che T è definita (ad esempio un int), la linea "iteratore i" funziona bene. Ma in quello che vedete sopra, g ++ su Ubuntu emette errori che non trovo molto istruttiva:

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 

La mia ipotesi è che questo è un problema di qualificazione tipo con un po 'di spin modello-y io non sono a conoscenza. Ho provato tutti i tipi di cose come:

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

ma niente sembra funzionare.

Qualche suggerimento?

+0

Quale compilatore stai utilizzando? Sono in grado di compilarlo su VC++ 2010. – Jagannath

+0

Ha già detto g ++ - VC++ è tradizionalmente molto lassista riguardo ai nomi dipendenti senza 'typename' o' template'. –

+0

Scusatemi, mi dispiace. – Jagannath

risposta

9

iterator è un tipo dipendente (dipende da un argomento modello) e deve essere preceduto da typename:

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

Meglio stile sarebbe quello di fornire una vasta classe typedef:

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

Che risolto! gf, tu sei un gentiluomo e uno studioso! –

3

Penso a gf has your answer, ma mi piacerebbe suggerire che la regione gestisca un elenco come membro anziché come classe 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; 
    } 
    ... 
}; 

La mia motivazione per questo suggerimento è che potresti, un giorno, voler utilizzare un contenitore diverso per conservare i tuoi KRects, e avere l'elenco come membro interno ti permetterebbe di farlo senza infrangere tutto il tuo codice cliente.

+0

e.James, sei anche un gentiluomo e uno studioso! Questa è una grande idea; tuttavia, al momento desidero che i client abbiano accesso diretto ai membri della lista perché sono troppo pigro per scrivere tutti gli accessor. :-) –

+0

Questo è assolutamente giusto ':)' Siamo stati tutti lì. –

+0

Spero solo che nessun cliente scriva mai 'ListType * l = new KRegion (); cancella l; '... –

Problemi correlati