C ++ 11 Rétrécissement variable sans avertissement du compilateur GCC

Le concept de rétrécissement semble assez simple. Cependant, quelqu’un pourrait-il s’il vous plaît expliquer pourquoi une partie du code ci-dessous provoque le “rétrécissement” des erreurs du compilateur et d’autres non?

Ce code produit des erreurs où prévu:

constexpr int a = 255; unsigned char b = a; // OK unsigned char c = a + 1; // Error... expected 

Ce code ne produit pas d’erreur, mais peut être ok:

 int d = 256; unsigned char e = d; // Maybe OK because 'd' is not constexpr 

Ce code devrait générer des erreurs (sauf s’il me manque quelque chose):

 int f = 42.0; // Maybe OK because no fractional part int g = 42.1; // OK... should fail!! constexpr float h = 42.7; int i = h; // OK... should fail??? 

J’utilise g ++ 4.6.2. J’ai cherché dans la firebase database de bogues GCC et je n’ai rien trouvé de pertinent. Merci!

Pour être honnête, avec vos échantillons, je vois un petit problème.

Cependant, il existe un certain nombre de cas où le compilateur semble accepter les “violations” des règles de conversion standard …:

Listes d’initialisation (§ 8.5.4)

Cependant, j’ai repéré celui-ci dans la norme:

Pour les listes d’initialisation, ce qui suit n’est pas autorisé (§ 8.5.4, sous 3. )

 int ai[] = { 1, 2.0 }; // error narrowing 

Le point 6 ci-dessous donne une liste générale d’exemples:

[Remarque: comme indiqué ci-dessus, ces conversions ne sont pas autorisées au niveau supérieur dans les initialisations de liste. — note de fin]

 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 

Fait intéressant, g ++ 4.6.1 avec --std=c++0x -Wall -pedantic n’attrape qu’une de ces violations:

  char c3{y}; // warning: overflow in implicit constant conversion [-Woverflow] 

En dehors des listes d’initialisation …

Je ne pense pas que la troncature d’un float à un int soit considérée comme un narrowing .

C’est juste une conversion bien définie, un peu comme

 int i = 31; i /= 4; // well defined loss of precision... i /= 4.0; // equally well-defined conversion from floating point to int 

Les points flottants peuvent être convertis en ints:

Une valeur d’un type à virgule flottante peut être convertie en une valeur d’un type entier. La conversion trône; c’est-à-dire que la partie décimale est rejetée. Le comportement est indéfini si la valeur tronquée ne peut pas être représentée dans le type de destination.

 int f = 42.0; // Equal to 42, 42 fits into int int g = 42.1; // Equal to 42, 42 fits constexpr float h = 42.7; int i = h; // 42 

Les règles ressortingctives ne s’appliquent qu’aux listes d’initialiseurs.

 unsigned char c = { 2.4 }; // narrowing warning: narrowing conversion of '2.3999999999999999e+0' from 'double' to 'unsigned char' inside { } [-Wnarrowing] 

Ce code produit des erreurs où prévu:

 constexpr int a = 255; unsigned char b = a; // OK unsigned char c = a + 1; // Error... expected 

Cela entraîne une erreur de limitation parce que:
1. (a + 1) se traduit par une valeur int
2. la rvalue ne rentre pas dans la plage valide du type char

 int d = 256; unsigned char e = d; // Maybe OK because 'd' is not constexpr 

Ce code n’est pas une valeur en cours de rétrécissement. C’est une conversion implicite de int en unsigned char.