que lenguaje enum c++ enums scope nested

c++ - lenguaje - espacios de nombres para tipos enum: mejores prácticas



que es un enum en java (8)

Dado que las enumeraciones tienen un alcance delimitador, probablemente sea mejor envolverlas en algo para evitar contaminar el espacio de nombre global y evitar las colisiones de nombres. Prefiero un espacio de nombres para clase simplemente porque el namespace siente como una bolsa de espera, mientras que la class siente como un objeto robusto (véase el debate de la struct frente a la class ). Un posible beneficio para un espacio de nombres es que se puede extender más adelante, lo cual es útil si se trata de un código de terceros que no se puede modificar.

Esto es discutible, por supuesto, cuando recibimos clases enum con C ++ 0x.

A menudo, uno necesita varios tipos enumerados juntos. A veces, uno tiene un choque de nombres. Dos soluciones a esto vienen a la mente: use un espacio de nombres, o use nombres de elementos enum ''más grandes''. Aún así, la solución de espacio de nombres tiene dos posibles implementaciones: una clase ficticia con enum anidado o un espacio de nombres completo.

Estoy buscando pros y contras de los tres enfoques.

Ejemplo:

// oft seen hand-crafted name clash solution enum eColors { cRed, cColorBlue, cGreen, cYellow, cColorsEnd }; enum eFeelings { cAngry, cFeelingBlue, cHappy, cFeelingsEnd }; void setPenColor( const eColors c ) { switch (c) { default: assert(false); break; case cRed: //... break; case cColorBlue: //... //... } } // (ab)using a class as a namespace class Colors { enum e { cRed, cBlue, cGreen, cYellow, cEnd }; }; class Feelings { enum e { cAngry, cBlue, cHappy, cEnd }; }; void setPenColor( const Colors::e c ) { switch (c) { default: assert(false); break; case Colors::cRed: //... break; case Colors::cBlue: //... //... } } // a real namespace? namespace Colors { enum e { cRed, cBlue, cGreen, cYellow, cEnd }; }; namespace Feelings { enum e { cAngry, cBlue, cHappy, cEnd }; }; void setPenColor( const Colors::e c ) { switch (c) { default: assert(false); break; case Colors::cRed: //... break; case Colors::cBlue: //... //... } }


Definitivamente evitaría usar una clase para esto; use un espacio de nombres en su lugar. La pregunta se reduce a si usar un espacio de nombres o usar identificadores únicos para los valores enum. Personalmente, utilizaría un espacio de nombres para que mis identificaciones pudieran ser más cortas y, con suerte, más fáciles de explicar. Entonces el código de la aplicación podría usar una directiva ''using namespace'' y hacer todo más legible.

De tu ejemplo de arriba:

using namespace Colors; void setPenColor( const e c ) { switch (c) { default: assert(false); break; case cRed: //... break; case cBlue: //... //... } }


FYI En C ++ 0x hay una nueva sintaxis para casos como los que mencionaste (ver la página wiki de C ++ 0x )

enum class eColors { ... }; enum class eFeelings { ... };


He hibridado las respuestas anteriores a algo como esto: (EDITAR: Esto solo es útil para pre C ++ 11. Si estás usando C ++ 11, usa la enum class )

Tengo un gran archivo de encabezado que contiene todas las enumeraciones de proyectos, porque estas enumeraciones se comparten entre clases de trabajadores y no tiene sentido colocar las enumeraciones en las clases de trabajadores.

La struct evita al público: azúcar sintáctica, y el typedef permite declarar variables de estas enumeraciones dentro de otras clases de trabajadores.

No creo que usar un espacio de nombres sea de ninguna ayuda. Tal vez esto se debe a que soy un programador de C #, y allí tienes que usar el nombre de tipo de enumeración al hacer referencia a los valores, por lo que estoy acostumbrado.

struct KeySource { typedef enum { None, Efuse, Bbram } Type; }; struct Checksum { typedef enum { None =0, MD5 = 1, SHA1 = 2, SHA2 = 3 } Type; }; struct Encryption { typedef enum { Undetermined, None, AES } Type; }; struct File { typedef enum { Unknown = 0, MCS, MEM, BIN, HEX } Type; };

...

class Worker { File::Type fileType; void DoIt() { switch(fileType) { case File::MCS: ... ; case File::MEM: ... ; case File::HEX: ... ; } }


La ventaja de usar una clase es que puedes construir una clase completa sobre la misma.

#include <cassert> class Color { public: typedef enum { Red, Blue, Green, Yellow } enum_type; private: enum_type _val; public: Color(enum_type val = Blue) : _val(val) { assert(val <= Yellow); } operator enum_type() const { return _val; } }; void SetPenColor(const Color c) { switch (c) { case Color::Red: // ... break; } }

Como muestra el ejemplo anterior, al usar una clase puedes:

  1. prohibir (lamentablemente, no en tiempo de compilación) que C ++ permita un lanzamiento desde un valor no válido,
  2. establecer un valor predeterminado (distinto de cero) para las enumeraciones recién creadas,
  3. agregue métodos adicionales, como para devolver una representación de cadena de una opción.

Solo tenga en cuenta que necesita declarar operator enum_type() para que C ++ sepa cómo convertir su clase en enum subyacente. De lo contrario, no podrá pasar el tipo a una declaración de switch .


También tiendo a envolver mis enums en clases.

Como señala Richard Corden, el beneficio de una clase es que se trata de un tipo en el sentido c ++, por lo que puedes usarlo con plantillas.

Tengo una caja de herramientas especial :: clase Enum para mis necesidades que me especializo para todas las plantillas que proporcionan funciones básicas (principalmente: asignar un valor enum a std :: string para que las E / S sean más fáciles de leer).

Mi pequeña plantilla también tiene el beneficio adicional de verificar realmente los valores permitidos. El compilador es poco estricto al verificar si el valor realmente está en la enumeración:

typedef enum { False: 0, True: 2 } boolean; // The classic enum you don''t want to see around your code ;) int main(int argc, char* argv[]) { boolean x = static_cast<boolean>(1); return (x == False || x == True) ? 0 : 1; } // main

Siempre me molestó que el compilador no capte esto, ya que te queda un valor enum que no tiene sentido (y que no esperarás).

Similar:

typedef enum { Zero: 0, One: 1, Two: 2 } example; int main(int argc, char* argv[]) { example y = static_cast<example>(3); return (y == Zero || y == One || y == Two) ? 0 : 1; } // main

Una vez más main devolverá un error.

El problema es que el compilador ajustará la enumeración en la representación más pequeña disponible (aquí necesitamos 2 bits) y que todo lo que se ajusta en esta representación se considera un valor válido.

También existe el problema de que a veces preferiría tener un bucle en los valores posibles en lugar de un interruptor para que no tenga que modificar todos los cambios cada vez que agregue un valor a la enumeración.

En general, mi pequeño ayudante realmente facilita las cosas para mis enumeraciones (por supuesto, agrega un poco de sobrecarga) y solo es posible porque anoto cada enum en su propia estructura :)


Una diferencia entre usar una clase o un espacio de nombres es que la clase no se puede volver a abrir como lo hace un espacio de nombres. Esto evita la posibilidad de que se abuse del espacio de nombre en el futuro, pero también existe el problema de que no se puede agregar al conjunto de enumeraciones.

Un posible beneficio para usar una clase es que se pueden usar como argumentos de tipo de plantilla, que no es el caso para los espacios de nombres:

class Colors { public: enum TYPE { Red, Green, Blue }; }; template <typename T> void foo (T t) { typedef typename T::TYPE EnumType; // ... }

Personalmente, no soy fanático de usar , y prefiero los nombres completos, así que realmente no veo eso como un plus para los espacios de nombres. Sin embargo, esta probablemente no sea la decisión más importante que tomará en su proyecto.


Respuesta original de C ++ 03:

El beneficio de un namespace (en una class ) es que puede usar el using declaraciones cuando lo desee.

El problema con el uso de un namespace es que los espacios de nombres se pueden expandir a otras partes del código. En un proyecto grande, no se le garantiza que dos enumeraciones distintas no creen que se llamen eFeelings

Para un código de aspecto más simple, uso una struct , ya que presumiblemente quiere que los contenidos sean públicos.

Si estás haciendo alguna de estas prácticas, estás por delante de la curva y probablemente no necesites seguir investigando.

Consejo más nuevo, C ++ 11:

Si está utilizando C ++ 11 o posterior, la enum class verá implícitamente los valores enum dentro del nombre de la enumeración.

Con la enum class perderás conversiones implícitas y comparaciones con tipos de enteros, pero en la práctica eso puede ayudarte a marcar un código ambiguo o defectuoso.