2009-08-18 14 views
12

Ho qualche codice C++, in cui viene dichiarato il seguente enum:Esiste un paradigma noto per iterare i valori enum?

enum Some 
{ 
    Some_Alpha = 0, 
    Some_Beta, 
    Some_Gamma, 
    Some_Total 
}; 
int array[Some_Total]; 

I valori di Alpha, Beta e Gamma sono sequenziali, e volentieri utilizzare il seguente ciclo per scorrere attraverso di loro:

for (int someNo = (int)Some_Alpha; someNo < (int)Some_Total; ++someNo) {} 

Questo ciclo va bene, fino a quando decido di cambiare l'ordine delle dichiarazioni nell'enum, diciamo, rendendo Beta il primo valore e Alpha - il secondo. Ciò invalida l'intestazione del ciclo, perché ora devo ripetere da Beta a Total. Quindi, quali sono le migliori pratiche per iterare con enum? Voglio scorrere tutti i valori senza modificare le intestazioni del ciclo ogni volta. Mi viene in mente una soluzione:

enum Some 
{ 
    Some_Start = -1, 
    Some_Alpha, 
    ... 
    Some_Total 
}; 
int array[Some_Total]; 

e iterare da (Start + 1) al totale, ma sembra brutto e non ho mai visto qualcuno che fa nel codice. C'è qualche paradigma noto per iterare attraverso l'enum, o devo solo fissare l'ordine dei valori enum? (Facciamo finta, ho davvero alcune ragioni impressionante per cambiare l'ordine dei valori enum) ...

+0

Potrebbe fornire un esempio su quando è necessario? O è puramente teorico? – Zed

+0

Il mio codice dipende dalle decisioni del team dei progettisti. A volte cambiano idea sull'ordine degli elementi, presenti sullo schermo. Devo aggiornare i miei valori enum in base all'ordine corrente degli elementi ... – SadSido

+0

Normalmente non cambierai l'ordine, se lo fai, le cose che si basano su quell'ordine (se stai usando enumerazioni alle due estremità di un sistema di comunicazione, scrivendo i valori su un file/database) si interromperà. –

risposta

0
enum Some 
{ 
    Some_first_ = 0, 
    Some_Alpha = Some_first_, 
.... 
    Some_last_ 
}; 

Facendo quali è possibile concedere prima & ultimo non cambia mai fine

+11

Perché i doppi underscore? Quei nomi sono illegali in C++. –

+0

Cosa intendi per illegale? È usato solo per dare loro un accento speciale. E SadSido ha chiesto del paradigma e nessuno ti obbliga a violare la convenzione sul codice. – Dewfy

+6

I nomi che contengono il doppio trattino basso sono riservati dallo standard C++ per l'implementazione C++ - non è consentito utilizzarli nel proprio codice. –

0

Se non si utilizza qualsiasi assegnazioni, l'enumerazione è garantita come sequenziale a partire da 0 come prima. thers.

La cosa migliore che puoi fare è tenerli nell'ordine che vuoi nella definizione enum, e scorrere attraverso di essi con il ciclo for.

4

No, non c'è modo di fare questo perché non v'è alcuna garanzia che qualcuno non ha scritto il codice come:

enum Some 
{ 
    Some_Alpha = 0, 
    Some_Beta, 
    Some_Gamma = 42, 
    Some_Delta, 
    Some_Total 
}; 
+1

Come sbi ha sottolineato, esiste effettivamente un modo per farlo che può gestire bene un caso del genere. –

3

È possibile controllare questo article con la sua source code su come è possibile implementare questo con membri della classe statici.

+0

+1, le enumerazioni sono un tipo di dati troppo primitivo per iterare su di esse, dr. dobb viene in soccorso. – Ozan

+0

Ottimo articolo, grazie! Ricordo la discussione sul pattern "typesafe enum" in alcuni libri Java e questo è lo stesso per C++ – SadSido

0

Posiziono tutte le enumerazioni nel proprio spazio dei nomi. Esempio:

namespace Foo { 
enum Enum { 
    First=0, // must be sequential 
    Second, 
    Third, 
    End // must be last 
}; 
} 

in codice:

for (int i=Foo::First; i!=Foo::End; i++) { 
// do stuff 
} 

Questo perché C++ permette cose come questa (non testato in un compilatore):

enum Foo { 
Alpha = 1 
}; 

enum Bar { 
Beta = 2 
}; 

Foo foo = Beta; 

che è chiaramente sbagliata.

+1

Quasi le mie enumerazioni sono dichiarate all'interno delle classi, che forniscono l'ambito. In C++, la classe è l'unità di scoping di base, non lo spazio dei nomi. –

+0

Una classe che esiste solo per tenere un enume non sembra giusto. –

+1

Beh, nemmeno uno spazio dei nomi, per quanto mi riguarda. –

13

È possibile definire un operator++() per il proprio enum. Questo ha il vantaggio di utilizzare il ben noto paradigma degli operatori di incremento standard. :)

seconda che i enumerazioni sono contigue, è possibile trattarli come int o utilizzare un interruttore:

Some& operator++(Some& obj) 
{ 
# if YOUR_ENUMS_ARE_CONTIGUOUS 
    int i = obj; 
    if(++i > Some_Total) i = Some_Alpha; 
    return obj = static_cast<Some>(i); 
# else 
    switch(obj) 
    { 
    case Some_Alpha : obj = Some_Beta; break; 
    case Some_Beta : obj = Some_Gamma; break; 
    case Some_Gamma : obj = Some_Total; break; 
    case Some_Total : obj = Some_Alpha; break; 
    default: assert(false); // changed enum but forgot to change operator 
    } 
    return obj; 
# endif 
} 

Si noti che, se operator++() è definito, gli utenti probabilmente si aspettano un operator--(), anche.

1

In C++ 11 (e probabilmente prima), è possibile utilizzare il seguente hack, per rendere Some iterabile:

Some operator++(Some& s) { 
    return s = (Some)(std::underlying_type<Some>::type(x) + 1); 
} 
Some operator*(Some s) { 
    return s; 
} 
Some begin(Some s) { 
    return Some_Alpha; 

Some end(Some s) { 
    return Some_Gamma; 
} 

int main() { 
    // the parenthesis here instantiate the enum 
    for(const auto& s : Some()) { 
     // etc. etc. 
    } 
    return 0; 
} 

(Questa risposta è stata spudoratamente adattato da here.)

Problemi correlati