C ++ 0x hará que el siguiente código y un código similar estén mal formados, porque requiere una llamada conversión de restricción de a double
a a int
.
int a[] = { 1.0 };
Me pregunto si este tipo de inicialización se usa mucho en el código del mundo real. ¿Cuántos códigos se romperán con este cambio? ¿Es mucho esfuerzo arreglar esto en su código, si su código se ve afectado?
Para referencia, consulte 8.5.4 / 6 de n3225
Una conversión de restricción es una conversión implícita
- de 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
- de un tipo de número entero o de enumeración sin ámbito a un tipo de punto flotante, excepto cuando la fuente es una expresión constante y el valor real después de la conversión se ajustará al tipo de destino y producirá el valor original cuando se vuelva a convertir al tipo original, o
- de un tipo de número entero o tipo de enumeración sin ámbito a un tipo de número entero que no puede representar todos los valores del tipo original, excepto cuando la fuente es una expresión constante y el valor real después de la conversión se ajustará al tipo de destino y producirá el valor original cuando convertido de nuevo al tipo original.
c++
c++11
survey
aggregate-initialization
Johannes Schaub - litb
fuente
fuente
0
ya es un deint
todos modos.){
los inicializadores de llaves}
, y el único uso heredado de esos es para matrices y estructuras POD. Además, si el código existente tiene conversiones explícitas donde pertenecen, no se romperá.int a = 1.0;
sigue siendo válido.Respuestas:
Me encontré con este cambio importante cuando usé GCC. El compilador imprimió un error para un código como este:
void foo(const unsigned long long &i) { unsigned int a[2] = {i & 0xFFFFFFFF, i >> 32}; }
Afortunadamente, los mensajes de error fueron sencillos y la solución fue simple:
void foo(const unsigned long long &i) { unsigned int a[2] = {static_cast<unsigned int>(i & 0xFFFFFFFF), static_cast<unsigned int>(i >> 32)}; }
El código estaba en una biblioteca externa, con solo dos ocurrencias en un archivo. No creo que el cambio importante afecte mucho al código. Los novatos pueden conseguir confundido, sin embargo.
fuente
Me sorprendería y decepcionaría de mí mismo saber que cualquiera de los códigos C ++ que escribí en los últimos 12 años tenía este tipo de problema. Pero la mayoría de los compiladores habrían arrojado advertencias sobre cualquier "estrechamiento" en tiempo de compilación todo el tiempo, a menos que me falte algo.
¿También reducen las conversiones?
unsigned short b[] = { -1, INT_MAX };
Si es así, creo que pueden aparecer un poco más a menudo que su ejemplo de tipo flotante a tipo integral.
fuente
No me sorprendería tanto si alguien queda atrapado por algo como:
float ra[] = {0, CHAR_MAX, SHORT_MAX, INT_MAX, LONG_MAX};
(en mi implementación, los dos últimos no producen el mismo resultado cuando se vuelven a convertir a int / long, por lo tanto, se están reduciendo)
Sin embargo, no recuerdo haber escrito esto nunca. Solo es útil si una aproximación a los límites es útil para algo.
Esto también parece al menos vagamente plausible:
void some_function(int val1, int val2) { float asfloat[] = {val1, val2}; // not in C++0x double asdouble[] = {val1, val2}; // not in C++0x int asint[] = {val1, val2}; // OK // now do something with the arrays }
pero no es del todo convincente, porque si sé que tengo exactamente dos valores, ¿por qué ponerlos en matrices en lugar de solo
float floatval1 = val1, floatval1 = val2;
? Sin embargo, ¿cuál es la motivación, por qué debería compilarse (y funcionar, siempre que la pérdida de precisión esté dentro de una precisión aceptable para el programa), mientrasfloat asfloat[] = {val1, val2};
que no debería? De cualquier manera, estoy inicializando dos flotantes desde dos entradas, es solo que en un caso los dos flotantes son miembros de un agregado.Eso parece particularmente severo en los casos en que una expresión no constante da como resultado una conversión restringida aunque (en una implementación particular), todos los valores del tipo de origen se pueden representar en el tipo de destino y se pueden convertir de nuevo a sus valores originales:
char i = something(); static_assert(CHAR_BIT == 8); double ra[] = {i}; // how is this worse than using a constant value?
Suponiendo que no haya ningún error, presumiblemente la solución es siempre hacer explícita la conversión. A menos que esté haciendo algo extraño con las macros, creo que un inicializador de matriz solo aparece cerca del tipo de matriz, o al menos de algo que representa el tipo, que podría depender de un parámetro de plantilla. Entonces, un yeso debería ser fácil, aunque detallado.
fuente
Una instancia práctica que me he encontrado:
float x = 4.2; // an input argument float a[2] = {x-0.5, x+0.5};
El literal numérico es implícitamente lo
double
que provoca la promoción.fuente
float
hazlo escribiendo0.5f
. ;)float
era un parámetro typedef o de plantilla (al menos sin pérdida de precisión), pero el punto es que el código tal como está escrito funcionó con la semántica correcta y se convirtió en un error con C ++ 11. Es decir, la definición de "cambio radical".Intente agregar -Wno-narrowing a su CFLAGS, por ejemplo:
CFLAGS += -std=c++0x -Wno-narrowing
fuente
Los errores de conversión delimitados interactúan mal con las reglas implícitas de promoción de enteros.
Tuve un error con el código que parecía
struct char_t { char a; } void function(char c, char d) { char_t a = { c+d }; }
Lo que produce un error de conversión de estrechamiento (que es correcto según el estándar). La razón es que
c
ed
implícitamente se promueve aint
y el resultadoint
no se puede reducir a char en una lista de inicializadores.OTOH
void function(char c, char d) { char a = c+d; }
Por supuesto, todavía está bien (de lo contrario, se desataría el infierno). Pero sorprendentemente, incluso
template<char c, char d> void function() { char_t a = { c+d }; }
está bien y se compila sin una advertencia si la suma de cyd es menor que CHAR_MAX. Sigo pensando que esto es un defecto en C ++ 11, pero la gente piensa lo contrario, posiblemente porque no es fácil de arreglar sin deshacerse de la conversión de enteros implícita (que es una reliquia del pasado, cuando la gente escribía código me gusta
char a=b*c/d
y esperaba que funcionara incluso si (b * c)> CHAR_MAX) o reduciendo los errores de conversión (que posiblemente sean algo bueno).fuente
unsigned char x; static unsigned char const m = 0x7f; ... unsigned char r = { x & m };
<- reducción de la conversión dentro de {}. De Verdad? Entonces, ¿el operador & también convierte implícitamente caracteres sin firmar a int? Bueno, no me importa, todavía se garantiza que el resultado será un carácter sin firmar, argh.De hecho, fue un cambio radical, ya que la experiencia de la vida real con esta función ha demostrado que gcc había convertido el estrechamiento en una advertencia de un error en muchos casos debido a los problemas de la vida real al migrar las bases de código C ++ 03 a C ++ 11. Vea este comentario en un informe de error de gcc :
fuente
Parece que GCC-4.7 ya no da errores para reducir las conversiones, sino advertencias.
fuente