Enum vs Enum fuertemente tipado

Soy un principiante en la progtwigción de C ++.

Hoy me encuentro con un nuevo tema: enum fuertemente tipado. Lo he investigado un poco, pero hasta ahora no puedo averiguar por qué lo necesitamos y de qué sirve el mismo.

Por ejemplo si tenemos:

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

¿Por qué tenemos que escribir?

 enum class xyz{a, b, c}; 

¿Qué estamos tratando de hacer aquí? Mi duda más importante es cómo usarlo. ¿Podría darme un pequeño ejemplo que me haga entender?

OK, primer ejemplo: las enumeraciones de estilo antiguo no tienen su propio scope:

 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! 

En segundo lugar, se convierten implícitamente a tipos integrales, lo que puede conducir a un comportamiento extraño:

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

Finalmente, puede especificar el tipo integral subyacente de enums de C ++ 11:

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

Anteriormente, no se especificaba el tipo subyacente, lo que podría causar problemas de compatibilidad entre plataformas. Editar Se ha señalado en los comentarios que también se puede especificar el tipo integral subyacente de una enumeración de “estilo antiguo” en C ++ 11.

Hay un buen artículo sobre enumeraciones en esta página de IBM , es muy detallado y está bien escrito. Aquí hay algunos puntos importantes en pocas palabras:

Las enumeraciones delimitadas resuelven la mayoría de las limitaciones en las que se encuentran las enumeraciones regulares: tipo completo de seguridad, tipo subyacente bien definido, problemas de scope y statement directa.

  • Obtiene seguridad de tipo al no permitir todas las conversiones implícitas de enumeraciones con ámbito a otros tipos.
  • Obtiene un nuevo scope, y la enumeración ya no se encuentra en el scope adjunto, salvándose de los conflictos de nombres.
  • Las enumeraciones por scope le dan la capacidad de especificar el tipo subyacente de la enumeración, y para las enumeraciones de ámbito, se establece de forma predeterminada en int si elige no especificarlo.
  • Cualquier enum con un tipo subyacente fijo puede declararse hacia adelante.

Los valores de la enum class son realmente de tipo enum class , no tipo_inicial como para C-enumeraciones.

 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

Las enumeraciones exportan sus enumeradores al ámbito circundante. Esto tiene dos inconvenientes. En primer lugar, puede generar conflictos de nombres si dos enumeradores en enum diferentes declarados en el mismo ámbito tienen el mismo nombre; segundo, no es posible usar un enumerador con un nombre completamente calificado, incluido el nombre enum.

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

Las clases enum (“nuevas enumeraciones”, “enums fuertes”) abordan tres problemas con las enumeraciones tradicionales de C ++:

  1. las enums convencionales se enums implícitamente a int , lo que provoca errores cuando alguien no desea que una enumeración actúe como un entero.
  2. las enums convencionales exportan sus enumeradores al ámbito circundante, causando conflictos de nombres.
  3. El tipo subyacente de una enum no se puede especificar, lo que genera confusión, problemas de compatibilidad y hace imposible la statement de reenvío.

enum class (“enums fuertes”) está fuertemente tipada y tiene un scope:

 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 

Como se muestra, las enumeraciones tradicionales funcionan como siempre, pero ahora puede optar por calificar con el nombre de la enumeración.

Las nuevas enumeraciones son “clase enum” porque combinan aspectos de enumeraciones tradicionales (valores de nombres) con aspectos de clases (miembros con ámbito y ausencia de conversiones).

Ser capaz de especificar el tipo subyacente permite una interoperabilidad más simple y tamaños garantizados de enumeraciones:

 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 

También permite la statement anticipada de enumeraciones:

 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 

El tipo subyacente debe ser uno de los tipos enteros con signo o sin signo; el valor predeterminado es int .

En la biblioteca estándar, las clases enum se usan para:

  1. Correlación de códigos de error específicos de sistemas: en : enum class errc ;
  2. Indicadores de seguridad del puntero: en : enum class pointer_safety { relaxed, preferred, strict };
  3. Errores de flujo de E / S: en : enum class io_errc { stream = 1 };
  4. Manejo de errores de comunicaciones asíncronas: en : enum class future_errc { broken_promise, future_already_retrieved, promise_already_satisfied };

Varios de estos tienen operadores, como == definido.