A menudo, se necesitan varios tipos enumerados juntos. A veces, uno tiene un choque de nombres. Se me ocurren dos soluciones a esto: use un espacio de nombres o use nombres de elementos de enumeración 'más grandes'. Aún así, la solución de espacio de nombres tiene dos posibles implementaciones: una clase ficticia con enumeración anidada 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: //...
//...
}
}
enum e {...}
, las enumeraciones pueden ser anónimas, es decirenum {...}
, lo que tiene mucho más sentido cuando se incluye en un espacio de nombres o una clase.Respuestas:
Respuesta original de C ++ 03:
El beneficio de a
namespace
(sobre aclass
) es que puede usarusing
declaraciones cuando lo desee.El problema con el uso de un
namespace
es que los espacios de nombres se pueden expandir en otras partes del código. En un proyecto grande, no se le garantizaría que dos enumeraciones distintas no crean que se llamaneFeelings
Para un código de apariencia más simple, uso un
struct
, ya que presumiblemente desea que el contenido sea público.Si está realizando alguna de estas prácticas, está por delante de la curva y probablemente no necesite examinar esto más a fondo.
Más reciente, consejo de C ++ 11:
Si está utilizando C ++ 11 o posterior,
enum class
implícitamente abarcará los valores de enumeración dentro del nombre de la enumeración.Con
enum class
perderá conversiones implícitas y comparaciones con tipos enteros, pero en la práctica eso puede ayudarlo a descubrir código ambiguo o con errores.fuente
Para su información, en C ++ 0x hay una nueva sintaxis para casos como el que mencionó (consulte la página wiki de C ++ 0x )
fuente
Hibridé las respuestas anteriores a algo como esto: (EDITAR: Esto solo es útil para versiones anteriores a C ++ 11. Si está usando C ++ 11, use
enum class
)Tengo un archivo de encabezado grande que contiene todas las enumeraciones de mi proyecto, porque estas enumeraciones se comparten entre clases trabajadoras y no tiene sentido poner las enumeraciones en las clases trabajadoras.
El
struct
evita el público: sintáctica azúcar, y latypedef
deja en realidad se declara variables de estas enumeraciones dentro de otras clases obreras.No creo que el uso de un espacio de nombres ayude en absoluto. Tal vez esto se debe a que soy un programador de C #, y hay que tener para usar el nombre del tipo de enumeración cuando se refiere a los valores, así que estoy acostumbrado a ella.
...
fuente
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 de enumeración. Personalmente, usaría un espacio de nombres para que mis identificadores pudieran ser más cortos y, con suerte, más autoexplicativos. Luego, el código de la aplicación podría usar una directiva de 'uso de espacio de nombres' y hacer que todo sea más legible.
De su ejemplo anterior:
fuente
Colors someColor = Red;
, porque el espacio de nombres no constituye un tipo. En suColors::e someColor = Red;
lugar, tendría que escribir , lo cual es bastante contrario a la intuición.Colors::e someColor
incluso con astruct/class
si quisieras usarlo en unaswitch
declaración? Si usa un anónimoenum
, el conmutador no podrá evaluar unstruct
.const e c
parece difícil de leer :-) No hagas eso. Sin embargo, usar un espacio de nombres está bien.Una diferencia entre usar una clase o un espacio de nombres es que la clase no se puede volver a abrir como un espacio de nombres. Esto evita la posibilidad de que se abuse del espacio de nombres en el futuro, pero también existe el problema de que tampoco se puede agregar al conjunto de enumeraciones.
Un posible beneficio de usar una clase es que se pueden usar como argumentos de tipo de plantilla, lo que no es el caso de los espacios de nombres:
Personalmente, no soy un fanático del uso y prefiero los nombres completamente calificados, por lo que realmente no veo eso como una ventaja para los espacios de nombres. Sin embargo, probablemente esta no sea la decisión más importante que tomará en su proyecto.
fuente
La ventaja de usar una clase es que puede construir una clase completa sobre ella.
Como muestra el ejemplo anterior, al usar una clase puede:
Solo tenga en cuenta que debe declarar
operator enum_type()
para que C ++ sepa cómo convertir su clase en una enumeración subyacente. De lo contrario, no podrá pasar el tipo a unaswitch
declaración.fuente
Dado que las enumeraciones tienen un alcance en su alcance adjunto, probablemente sea mejor envolverlas en algo para evitar contaminar el espacio de nombres global y ayudar a evitar colisiones de nombres. Prefiero un espacio de nombres a una clase simplemente porque se
namespace
siente como una bolsa de tenencia, mientras que seclass
siente como un objeto robusto (cf. el debatestruct
vs.class
Un posible beneficio de un espacio de nombres es que se puede ampliar más adelante, lo que resulta útil si se trata de un código de terceros que no puede modificar.Por supuesto, todo esto es discutible cuando obtenemos clases de enumeración con C ++ 0x.
fuente
También tiendo a envolver mis enumeraciones en clases.
Como señaló Richard Corden, el beneficio de una clase es que es un tipo en el sentido de C ++ y, por lo tanto, puede usarlo con plantillas.
Tengo una caja de herramientas especial :: clase Enum para mis necesidades que me especializo para cada plantilla que proporciona funciones básicas (principalmente: mapear un valor de enumeración a un std :: string para que la E / S sea más fácil de leer).
Mi pequeña plantilla también tiene el beneficio adicional de verificar realmente los valores permitidos. El compilador es un poco laxo al verificar si el valor realmente está en la enumeración:
Siempre me molestó que el compilador no captara esto, ya que te queda un valor de enumeración que no tiene sentido (y que no esperas).
Similar:
Una vez más, main devolverá un error.
El problema es que el compilador encajará la enumeración en la representación más pequeña disponible (aquí necesitamos 2 bits) y que todo lo que encaje en esta representación se considera un valor válido.
También existe el problema de que a veces prefiere tener un bucle en los valores posibles en lugar de un interruptor para que no tenga que modificar todos los interruptores cada vez que agrega un valor a la enumeración.
Con todo, mi pequeño ayudante realmente facilita las cosas para mis enumeraciones (por supuesto, agrega algo de sobrecarga) y solo es posible porque anido cada enumeración en su propia estructura :)
fuente