c++ - static_cast - ¿Por qué "unsigned int ui={-1};" un error de conversión de reducción?
conversion de tipos de datos en c++ (1)
Seguramente -1, hay un entero constante y, si se convierte en unsigned y back, todavía produce int -1?
Esto está mal. Si convierte -1 a unsigned
obtendrá UINT_MAX
. Esto está bien porque la conversión a tipos sin firmar siempre está definida. Sin embargo, UINT_MAX
no cabe en int
y las conversiones a los tipos firmados solo están definidas por el estándar cuando el valor se ajusta al tipo de destino.
El Estándar en § 8.5.4 / 7 explica qué es una conversión de reducción :
Una conversión de reducción es una conversión implícita
- desde un tipo de punto flotante a un tipo entero, o
- de doble largo a doble o flotante, o de doble a flotante, excepto cuando la fuente es una expresión constante y el valor real después de la conversión está dentro del rango de valores que se pueden representar (incluso si no se puede representar exactamente), o
- desde un tipo de enteros o un tipo de enumeración sin cobertura hasta un tipo de coma flotante, excepto cuando el origen sea una expresión constante y el valor real después de la conversión se ajuste al tipo de destino y produzca el valor original cuando se vuelva a convertir al tipo original. o
- desde un tipo entero o un tipo de enumeración no codificado a un tipo entero que no puede representar todos los valores del tipo original, excepto cuando el origen es una expresión constante y el valor real después de la conversión se ajustará al tipo objetivo y generará el valor original cuando se convierte de nuevo al tipo original.
Luego, no permite dichas conversiones en algunos contextos de inicialización de listas, dando ejemplos:
[Nota: como se indicó anteriormente, dichas conversiones no están permitidas en el nivel superior en las inicializaciones de listas. - nota final] [Ejemplo:
int x = 999; // x is not a constant expression
const int y = 999;
const int z = 99;
char c1 = x; // OK, though it might narrow (in this case, it does narrow)
char c2{x}; // error: might narrow
char c3{y}; // error: narrows (assuming char is 8 bits)
char c4{z}; // OK: no narrowing needed
unsigned char uc1 = {5}; // OK: no narrowing needed
unsigned char uc2 = {-1}; // error: narrows
unsigned int ui1 = {-1}; // error: narrows
signed int si1 =
{ (unsigned int)-1 }; // error: narrows
int ii = {2.0}; // error: narrows
float f1 { x }; // error: might narrow
float f2 { 7 }; // OK: 7 can be exactly represented as a float
int f(int);
int a[] =
{ 2, f(2), f(2.0) }; // OK: the double-to-int conversion is not at the top level
- ejemplo final]
Los 7 errores ilustrados por los ejemplos se informan como tales por clang 3.2 / 3.3 con -std=c++11
, por ejemplo
error: non-constant-expression cannot be narrowed from type ''int'' to ''char'' in initializer list [-Wc++11-narrowing]
Ninguno de ellos se informa como errores por gcc 4.7.2 / 4.8.1, pero en cada caso se da una advertencia similar, por ej.
warning: narrowing conversion of ‘x’ from ‘int’ to ‘char’ inside { } [-Wnarrowing]
(Por lo tanto, gcc parece saber lo que exige el cumplimiento, pero opta por tolerar el incumplimiento por defecto).
Lo que no entiendo es cómo el ejemplo:
unsigned int ui1 = {-1}; // error: narrows
califica como un ejemplo. (Igualmente con el ejemplo si1
simétrico.) Evidentemente, las únicas palabras con las que podría calificarse como ejemplo son las del cuarto y último ítem en la definición de conversión de estrechamiento dada anteriormente; pero si es así, ¿por qué el ejemplo no escapa por la calificación, excepto cuando la fuente es una expresión constante y el valor real después de la conversión encajará en el tipo objetivo y producirá el valor original cuando se vuelva a convertir al tipo original ? Seguramente -1
hay un entero constante y, si se convierte en unsigned
y back, todavía produce int -1
?
¿Qué me estoy perdiendo?