2009-05-12 25 views
27

He estado tratando de leer un poco del estándar de C++ para descubrir cómo funciona enum. En realidad, hay más allí de lo que originalmente pensé.Tipo subyacente de una enumeración de C++ en C++ 0x

Para una enumeración con ámbito, está claro que el tipo subyacente es int a menos que se especifique lo contrario con una cláusula enum-base (puede ser de tipo integral).

enum class color { red, green, blue}; // these are int 

Para enumeraciones sin ámbito, parece que el tipo subyacente puede ser cualquier tipo integral que funciona y que no va a ser más grande que un int, a menos que tiene que ser.

enum color { red, green, blue}; // underlying type may vary 

Dado que el tipo subyacente de enumarations sin ámbito no están estandarizados, ¿cuál es la mejor manera de hacer frente a serializar instancias de uno? Hasta ahora, he estado convirtiendo a int al escribir y luego serializar en un int y estableciendo mi variable enum en un interruptor al leer, pero parece un poco torpe. ¿Hay una mejor manera?

enum color { red, green, blue }; 
color c = red; 
// to serialize 
archive << (int)c; 
// to deserialize 
int i; 
archive >> i; 
switch(i) { 
    case 0: c = red; break; 
    case 1: c = green; break; 
    case 2: c = blue; break; 
} 
+2

clase de enumeración es solamente C++ 0x ... – Klaim

+2

1, no sé por qué esta pregunta se -1ed ... –

+1

Posiblemente porque el que pregunta aparentemente no puede diferenciar entre una ya existente y un documento de estándares propuestos? –

Respuesta

5

No he leído nada de C++ 0x, así que no pude comentar sobre eso.

En cuanto a la serialización, no necesita el conmutador al leer la enumeración de nuevo, simplemente transfiéralo al tipo enum.

Sin embargo, no selecciono cuando escribo en la transmisión. Esto se debe a que a menudo me gusta escribir un operador < < para la enumeración, así puedo capturar los valores incorrectos que se escriben, o puedo decidir escribir una cadena en su lugar.

enum color { red, green, blue }; 
color c = red; 

// to serialize 
archive << c; // Removed cast 

// to deserialize 
int i; 
archive >> i; 
c = (color)i; // Removed switch 
+1

Gracias por la idea de escribir un operador << para la enumeración. Debería haberlo pensado yo mismo. – criddell

+0

En su comentario, mencionó que escribió un operador << y entiendo que su código anterior funcionaría correctamente con esa sobrecarga en su lugar. Sin embargo, si << no están sobrecargados, uno debe convertir c en un int antes de serializar, ¿correcto? – criddell

+0

No No lanzaría a int porque si lo hizo y luego agregó el operador enum << más tarde, debe buscar todos los lugares en el código que escribe la enumeración y eliminar el reparto. – markh44

16

clase enum es una característica C++0x, no está presente en C++ 03.

En el estándar C++, las enumeraciones no son seguras para tipos. En realidad son enteros, incluso cuando los tipos de enumeración son distintos. Esto permite la comparación entre dos valores enum de diferentes tipos de enumeración. La única seguridad que proporciona C++ 03 es que un entero o un valor de un tipo de enumeración no convierte implícitamente a otro tipo de enumeración. Además, el tipo integral subyacente, el tamaño del número entero, no se puede especificar explícitamente; es implementación definida. Por último, los valores de enumeración tienen un alcance dentro del alcance adjunto. Por lo tanto, no es posible que dos enumeraciones separadas tengan nombres de miembros coincidentes. C++ 0x permitirá una clasificación especial de enumeración que no tenga ninguno de estos problemas. Esto se expresa mediante la declaración de clase de enumeración

ejemplos (del artículo de Wikipedia):

enum Enum1;     //Illegal in C++ and C++0x; no size is explicitly specified. 
enum Enum2 : unsigned int; //Legal in C++0x. 
enum class Enum3;    //Legal in C++0x, because enum class declarations have a default type of "int". 
enum class Enum4: unsigned int; //Legal C++0x. 
enum Enum2 : unsigned short; //Illegal in C++0x, because Enum2 was previously declared with a different type. 

En cuanto a la parte de serialización (que creo que no era parte de la pregunta original), prefiero cree una clase auxiliar que traduzca elementos enum a su equivalente de cadena (y viceversa), ya que los nombres suelen ser más estables que los valores enteros que representan, ya que los elementos enum pueden reordenarse (y algunas veces se reordenan) sin cambiar el comportamiento del código.

1

En cuanto a enum class color: ¿Esto es C++/CLI (C++ .NET) o futuro código de C++ 0x?

Para la serialización, puede obtener el tamaño de la enumeración con sizeof(color) para saber cuántos bytes copiar.

14

Decidí crear una nueva respuesta porque mi edad era muy desordenada. De todos modos sólo quiero decir algo acerca de C++ 11, donde se puede obtener el tipo subyacente de una enumeración utilizando éste:

std::underlying_type_t<E> 

Y por el bien de su interés, la idea de resolución de sobrecarga. Pero use nombres para almacenar la enumeración, tal como lo propone @lothar.

La resolución de sobrecarga se debe al hecho de que existe una promoción de una enumeración al primero de int, unsigned int, long, unsigned long que puede representar todos los valores de su tipo subyacente. Una conversión a cualquier otro tipo de entero es de menor rango y la resolución de sobrecarga no lo preferirá.

char (& f(int))[1]; 
char (& f(unsigned int))[2]; 

char (& f(long))[3]; 
char (& f(unsigned long))[4]; 

char const* names[] = { 
    "int", "unsigned int", 
    "long", "unsigned long" 
}; 

enum a { A = INT_MIN }; 
enum b { B = UINT_MAX }; 
enum c { C = LONG_MIN }; 
enum d { D = ULONG_MAX }; 

template<typename T> void print_underlying() { 
    std::cout << names[sizeof(f(T()))-1] << std::endl; 
} 

int main() { 
    print_underlying<a>(); 
    print_underlying<b>(); 
    print_underlying<c>(); 
    print_underlying<d>(); 
} 

e imprime este de aquí:

int 
unsigned int 
int 
unsigned int 

No es de particular interés para este problema de serialización (ya que el tamaño de los datos serializados no es de anchura constante, y esto puede causar problemas cuando se cambia la enumeración y su tipo subyacente), pero en general es interesante determinar un tipo que almacena toda la enumeración. ¡Aclamaciones!

+0

'std :: underlying_type' es la mejor solución para obtener el tipo correcto. Solo una pequeña corrección: el helper ** 'std :: underlying_type_t ' ** está disponible a través de ** C++ 14 **; para ** C++ 11 ** tienes que usar ** 'std :: underlying_type :: type' ** en su lugar. – ollo

5
#include <type_traits> 

enum a { bla1, bla2 }; 
typedef typename std::underlying_type<a>::type underlying_type; 

if (std::is_same<underlying_type, int>::value) 
    std::cout << "It's an int!" << endl; 
else if (std::is_same<underlying_type, unsigned int>::value) 
    std::cout << "It's an uint!" << endl; 
+2

Es costumbre usar el texto para explicar qué está haciendo algo, en lugar de solo regurgitar un bloque de código. –

+0

Haré una puñalada en una explicación. El código está usando un poco de magia de plantilla para que el compilador descubra el tipo subyacente de la enumeración. Le pregunté cómo averiguar el tipo subyacente para propósitos de serialización y este código lo haría. – criddell