Enum contro enum fortemente tipizzato

Sono un principiante nella programmazione in C ++.

Oggi mi imbatto in un nuovo argomento: enum fortemente tipizzato. Ho studiato un po ‘ma fino ad ora non riesco a scoprire perché ne abbiamo bisogno e a che cosa serve lo stesso?

Ad esempio se abbiamo:

 enum xyz{a, b, c}; /*a = 0, b = 1, c = 2, (Typical C format)*/ 

Perché abbiamo bisogno di scrivere:

 enum class xyz{a, b, c}; 

Cosa stiamo cercando di fare qui? Il mio dubbio più importante è come usarlo. Potresti fornire un piccolo esempio, che mi farà capire.

OK, primo esempio: le enumerazioni vecchio stile non hanno il loro scopo:

 enum Animals {Bear, Cat, Chicken}; enum Birds {Eagle, Duck, Chicken}; // error! Chicken has already been declared! enum class Fruits { Apple, Pear, Orange }; enum class Colours { Blue, White, Orange }; // no problem! 

In secondo luogo, implicitamente convertono in tipi interi, che possono portare a comportamenti strani:

 bool b = Bear && Duck; // what? 

Infine, puoi specificare il tipo integrale sottostante di enumerazioni C ++ 11:

 enum class Foo : char { A, B, C}; 

In precedenza, il tipo sottostante non è stato specificato, il che potrebbe causare problemi di compatibilità tra piattaforms. Modifica È stato sottolineato nei commenti che è ansible specificare anche il tipo integrale sottostante di un enum “vecchio stile” in C ++ 11.

C’è un buon articolo sull’enumerazione in questa pagina IBM , è molto dettagliato e ben scritto. Ecco alcuni punti importanti in poche parole:

Le enunciate dell’ambito risolvono la maggior parte dei limiti incontrati dalle normali enumerazioni: sicurezza completa del tipo, tipo sottostante ben definito, problemi di ambito e dichiarazione anticipata.

  • Ottieni la sicurezza del tipo impedendo tutte le conversioni implicite di enumerazione dell’ambito ad altri tipi.
  • Si ottiene un nuovo ambito e l’enumerazione non è più nell’intervallo di chiusura, salvandosi dai conflitti di nome.
  • Le enumerazioni scopate ti danno la possibilità di specificare il tipo sottostante dell’enumerazione e, per le enumerazioni dell’ambito, assume come valore predefinito int se si sceglie di non specificarlo.
  • Qualsiasi enume con un tipo sottostante fisso può essere dichiarato dichiarato.

I valori della enum class sono in realtà di tipo enum class , non di underlying_type come per enumerazione C.

 enum xyz { a, b, c}; enum class xyz_c { d, f, e }; void f(xyz x) { } void f_c(xyz_c x) { } // OK. f(0); // OK for C++03 and C++11. f(a); // OK with C++11. f(xyz::a); // ERROR. f_c(0); // OK. f_c(xyz_c::d); 

Enum Scope

Le enumerazioni esportano i loro enumeratori nello scope circostante. Questo ha due inconvenienti. In primo luogo, può portare a conflitti di nomi, se due enumeratori in enumerazioni diverse dichiarate nello stesso ambito hanno lo stesso nome; in secondo luogo, non è ansible utilizzare un enumeratore con un nome completo, incluso il nome enum.

 enum ESet {a0, a, a1, b1, c3}; enum EAlpha{a, b, c} select = ESet::a; // error select = a; // is ambigious 

Le classi enum (“nuove enumerazioni”, “forti enumerazioni”) affrontano tre problemi con le tradizionali enumerazioni C ++:

  1. le enums convenzionali si enums implicitamente in int , causando errori quando qualcuno non vuole che un’enumerazione agisca come un intero.
  2. le enums convenzionali enums i loro enumeratori nello scope circostante, causando conflitti di nomi.
  3. Il tipo sottostante di enum non può essere specificato, causando confusione, problemi di compatibilità e rende imansible la dichiarazione anticipata.

enum class (“enumerazioni forti”) sono fortemente tipizzati e con ambito:

 enum Alert { green, yellow, orange, red }; // traditional enum enum class Color { red, blue }; // scoped and strongly typed enum // no export of enumerator names into enclosing scope // no implicit conversion to int enum class TrafficLight { red, yellow, green }; Alert a = 7; // error (as ever in C++) Color c = 7; // error: no int->Color conversion int a2 = red; // ok: Alert->int conversion int a3 = Alert::red; // error in C++98; ok in C++11 int a4 = blue; // error: blue not in scope int a5 = Color::blue; // error: not Color->int conversion Color a6 = Color::blue; // ok 

Come mostrato, le enumerazioni tradizionali funzionano come al solito, ma ora puoi opzionalmente qualificarti con il nome dell’enum.

Le nuove enumerazioni sono “enum class” perché combinano aspetti delle enumerazioni tradizionali (valori dei nomi) con aspetti delle classi (membri dell’ambito e assenza di conversioni).

Essere in grado di specificare il tipo sottostante consente un’interoperabilità più semplice e dimensioni di enumerazioni garantite:

 enum class Color : char { red, blue }; // compact representation enum class TrafficLight { red, yellow, green }; // by default, the underlying type is int enum E { E1 = 1, E2 = 2, Ebig = 0xFFFFFFF0U }; // how big is an E? // (whatever the old rules say; // ie "implementation defined") enum EE : unsigned long { EE1 = 1, EE2 = 2, EEbig = 0xFFFFFFF0U }; // now we can be specific 

Abilita anche la dichiarazione anticipata di enumerazioni:

 enum class Color_code : char; // (forward) declaration void foobar(Color_code* p); // use of forward declaration // ... enum class Color_code : char { red, yellow, green, blue }; // definition 

Il tipo sottostante deve essere uno dei tipi interi con segno o senza segno; il valore predefinito è int .

Nella libreria standard, le classi enum vengono utilizzate per:

  1. Codici di errore specifici per i sistemi di mapping: In : enum class errc ;
  2. Indicatori di sicurezza del puntatore: in : enum class pointer_safety { relaxed, preferred, strict };
  3. Errori di stream I / O: In : enum class io_errc { stream = 1 };
  4. Gestione degli errori di comunicazione asincrona: In : enum class future_errc { broken_promise, future_already_retrieved, promise_already_satisfied };

Molti di questi hanno operatori, come == definito.