uniones tipos programacion imprimir español enumerados enumeraciones enum ejemplo crear c++ enums initialization language-lawyer value-initialization

c++ - tipos - typedef enum c ejemplo



El comportamiento de la inicialización de valor de una enumeración (2)

1: Esto puede ser comprendido así:

enum class SomeEnum : int { V1 = 0, V2 = 1, V3 = 2 }; SomeEnum a = 0; // compile error SomeEnum b = SomeEnum.V1; // OK

¡Esta es una protección básica contra un comportamiento indefinido!

2: Sí y sí :)

SomeEnum c = static_cast<SomeEnum>(1); // = SomeEnum.V2 SomeEnum d = static_cast<SomeEnum>(5); // undefined behavior

¡static_cast es peligroso por definición, solo se debe usar para admitir la serialización o las interfaces antiguas!

Primero, quiero decir, de acuerdo con cppreference.com, es un tanto imposible inicializar con valor una enumeración.

De acuerdo con http://en.cppreference.com/w/cpp/language/value_initialization , la inicialización de valores de una enumeración realmente realiza una inicialización de cero. Luego se sigue que, de acuerdo con http://en.cppreference.com/w/cpp/language/zero_initialization , el efecto de la inicialización cero de una enumeración es:

Si T es un tipo escalar, el valor inicial del objeto es la constante integral cero convertida implícitamente en T

Sin embargo, una constante constante cero no se puede convertir implícitamente en una enumeración. En última instancia, una enumeración no se puede inicializar con valores. Esto suena raro, y la inicialización de valores de una enumeración funciona en VC, GCC y clang. Entonces, ¿qué dice la norma sobre esto?

En segundo lugar, según http://en.cppreference.com/w/cpp/language/static_cast :

El tipo entero, punto flotante o enumeración se puede convertir a cualquier tipo de enumeración completa (el resultado es un comportamiento no especificado (hasta C ++ 17) indefinido (desde C ++ 17) si el valor de expresión se convirtió al tipo subyacente de la enumeración). , no es uno de los valores de enumeración de destino)

Entonces, ¿esto implica que la inicialización de valores de una enumeración (si funciona) puede llevar a un comportamiento indefinido si la enumeración de destino no tiene un enumerador igual a 0 ?


La respuesta a esto fue dada en los comentarios. Mi intento de explicar todo el standardese detrás de esto se da a continuación.

Para inicializar en cero un objeto o referencia de tipo T significa:

  • si T es un tipo escalar (3.9), el objeto se inicializa al valor obtenido al convertir el literal entero 0 (cero) a T ;

(Las enumeraciones son tipos escalares; §3.9 / 9) Entonces, como no se dice que la conversión sea implícita, no estamos buscando en §4, sino en §5.2.9;

El resultado de la expresión static_cast<T>(v) es el resultado de convertir la expresión v al tipo T

§5.2.9 / 10 luego define cómo los valores integrales se convierten a tipos de enumeración.

Un valor de tipo integral o de enumeración se puede convertir explícitamente a un tipo de enumeración. El valor no cambia si el valor original está dentro del rango de los valores de enumeración (7.2) . De lo contrario, el valor resultante no se especifica (y puede que no esté en ese rango).

Se debe mostrar que cero está en el rango de valores de enumeración para todas las enumeraciones.
Las siguientes cinco citas están tomadas de §7.2 / 8:

Para una enumeración cuyo tipo subyacente es fijo, los valores de la enumeración son los valores del tipo subyacente.

Dado que todos los tipos subyacentes permitidos incluyen cero en su rango de valores *, esto da automáticamente el resultado deseado. Ahora, para las enumeraciones sin tipos subyacentes fijos,

De lo contrario, para una enumeración donde e min es el enumerador más pequeño y e max es el más grande, los valores de la enumeración son los valores en el rango de b min a b max , definidos de la siguiente manera:

Es decir, tenemos que demostrar que b min es siempre menor o igual a cero, y b max siempre es mayor o igual a cero.

Sea K 1 para una representación de complemento a dos y 0 para una representación de complemento o de magnitud de signo.
b max es el valor más pequeño mayor o igual que max (| e min | - K, | e max |) e igual a 2M - 1 , donde M es un número entero no negativo.

| e max | no es negativo, y el máximo de dos números es al menos tan grande como lo son ambos números. Por lo tanto, max (| e min | - K, | e max |) tampoco es negativo, y b max debe ser mayor o igual a ese número, por lo que se cumple nuestro primer requisito.

b min es cero si e min no es negativo y - (b max + K) de lo contrario.

b min es claramente cero o negativo: b max no es negativo como se muestra arriba, y K no es negativo (0 o 1), por lo tanto, el inverso aditivo de su suma no es positivo. Nuestro segundo requisito se cumple. Finalmente,

Si la lista de enumeradores está vacía, los valores de la enumeración son como si la enumeración tuviera un solo enumerador con valor 0 .

Esto conduce al resultado anterior al configurar e min = e max = 0 .

  • Esto se reduce a la afirmación "Todos los tipos integrales tienen cero en su rango de valores", que queda por demostrar para el lector.