En la versión C++11 se agregó la característica de poder inicializar objetos usando las llaves. Esta sintaxis sirve tanto para objetos como para datos primitivos: enteros, flotantes, double…
int i {0}
double pi{3.1416}
string mensaje{"Hola mundo"}
Coordenada2D origen{0, 0};
Este tipo de inicialización se llama inicialización uniforme y una de las cosas importantes que introduce es que no permite la conversión implicita entre tipos.
int pi = 3.1416; //No lanza error al compilar. Solo usará 3, que es la parte entera.
int pi {3.1416}; //Lanzará un error al compilar, no se puede convertir un número
flotante en entero.
El fragmento de código anterior es válido y compila sin ningún tipo de warning. La variable pi tendrá como valor el entero tres. Veamos otro ejemplo inocente.
class EnteroSinSigno {
public:
EnteroSinSigno(unsigned int e): e(e) {}
unsigned int e;
};
...
EnteroSinSigno e(-1);
Pues sí, este código es perfectamente válido y compila sin lanzar ningún warning por que se está realizando una conversión implícita por debajo. Es evidente que no deberia compilar, el constructor espera un entero sin signo y estamos construyendo el objeto con nada menos que un número negativo.
La solución es habituarnos a inicializar las variables usando las llaves. De esta manera el compilador si que devuelve un error y nos tira a la cara el error que estamos cometiendo:
EnteroSinSigno e{-1}; //narrowing conversion of ‘-1’ from ‘int’ to ‘unsigned int’[-Wnarrowing]
Enlaces
http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-narrowing