Почему "unsigned int ui = {-1};" сужающаяся ошибка преобразования?
Стандарт в п. 8.5.4/7 объясняет, что такое сужающее преобразование:
Сужающее преобразование - это неявное преобразование
- от типа с плавающей точкой к целочисленному типу, или
- от long double до double или float, или от double до float, за исключением случаев, когда источником является постоянное выражение, а фактическое значение после преобразования находится в диапазоне значений, которые могут быть представлены (даже если они не могут быть представлены точно), или
- от целочисленного типа или типа перечисления с незаданной областью до типа с плавающей запятой, за исключением случаев, когда источником является константное выражение, а фактическое значение после преобразования будет соответствовать целевому типу и будет выдавать исходное значение при преобразовании обратно в исходный тип, или же
- от целочисленного типа или типа перечисления с незаданной областью до целочисленного типа, который не может представлять все значения исходного типа, за исключением случаев, когда источником является константное выражение, а фактическое значение после преобразования будет соответствовать целевому типу и будет создавать исходное значение при преобразовании обратно в исходный тип.
Затем он запрещает такие преобразования в некоторых контекстах инициализации списка, приводя примеры:
[Примечание: как указано выше, такие преобразования не допускаются на верхнем уровне при инициализации списка. - примечание конца] [Пример:
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
- конец примера]
Все 7 ошибок, проиллюстрированных примерами, сообщаются как таковые clang 3.2/3.3 с -std=c++11
например,
error: non-constant-expression cannot be narrowed from type 'int' to 'char' in initializer list [-Wc++11-narrowing]
GCC 4.7.2/4.8.1 не сообщает ни об одном из них как об ошибках, но в каждом случае выдается похожее предупреждение, например
warning: narrowing conversion of ‘x’ from ‘int’ to ‘char’ inside { } [-Wnarrowing]
(таким образом, gcc, кажется, знает, что требует соответствия, но по умолчанию предпочитает терпеть несоответствие.)
То, что я не понимаю, это как пример:
unsigned int ui1 = {-1}; // error: narrows
квалифицируется как пример. (Аналогично с симметричным si1
пример.) Очевидно, что единственными словами, которыми он может быть квалифицирован как пример, являются слова четвертого и последнего пункта в приведенном выше определении сужающего преобразования; но если это так, то почему пример не уходит от квалификации, кроме случаев, когда источником является константное выражение, а фактическое значение после преобразования будет соответствовать целевому типу и будет выдавать исходное значение при преобразовании обратно в исходный тип? конечно -1
есть целочисленная константа и, если преобразовано в unsigned
и обратно, по-прежнему дает int -1
?
Что мне не хватает?
1 ответ
Конечно, -1 есть целочисленная константа, и, если она преобразована в unsigned и обратно, все равно возвращает int -1?
Это не верно. Если вы конвертируете -1 в unsigned
ты получаешь UINT_MAX
, Это хорошо, потому что преобразование в неподписанные типы всегда определяется. Тем не мение, UINT_MAX
не вписывается в int
и преобразования в подписанные типы определяются стандартом только тогда, когда значение соответствует целевому типу.