Это выражение можно найти в примере в §8.5.4 / 7 в стандарте (N3797)
unsigned int ui1 = {-1}; // error: narrows
Учитывая §8.5.4 / 7 и его четвертый пункт маркированного списка:
Сужающее преобразование — это неявное преобразование:
- от целочисленного типа или перечислимого типа с незаданной областью до целочисленного типа, который не может представлять все значения исходного типа,
кроме случаев, когда источником является константное выражение, значение которого после
интегральные рекламные акции будут соответствовать целевому типу.
Я бы сказал, что здесь нет сужения, так как -1 — это константное выражение, значение которого после интегрального продвижения помещается в беззнаковое целое.
Смотрите также §4.5 / 1 о Интегральное продвижение:
Значение типа integer, отличное от bool, char16_t, char32_t или
wchar_t, чей ранг преобразования целых чисел (4.13) меньше, чем ранг
int может быть преобразовано в значение типа int, если int может представлять все
значения типа источника; в противном случае исходное значение может быть
преобразуется в значение типа unsigned int.
Из 4.13 мы имеем, что ранг -1 (целое число) равен рангу целого без знака, и поэтому он может быть преобразован в целое число без знака.
редактировать
к несчастью Джерри Гроб удалил свой ответ из этой ветки. Я полагаю, что он был на правильном пути, если мы примем тот факт, что текущее чтение пункта 4 пули в §8.5.4 / 7 неверно, после этого менять в стандарте.
Изменение в формулировке стандарта призвано подтвердить понимание того, что преобразование отрицательного значения в тип без знака является и всегда было сужающим преобразованием.
Неформально, -1 не может быть представлен в диапазоне любого беззнакового типа, и битовый шаблон, который представляет это, не представляет то же самое значение, если сохранено в беззнаковом int. Поэтому это сужение конверсии и продвижение / расширение не участвует.
Это о изящном искусстве чтения стандарта. Как обычно, компилятор знает лучше.
Там нет целостного продвижения от int
в unsigned int
для этого он все еще плохо информирован.
Это было бы интеграл преобразование.
Сужение — это неявное преобразование целочисленного типа в целочисленный тип, который не может представлять все значения исходного типа.
Преобразование из целочисленного типа int
целочисленный тип unsigned int
Конечно, не может представлять все значения исходного типа — стандарт здесь совершенно однозначен. Если вам это действительно нужно, вы можете сделать
unsigned int ui1 = {-1u};
Это работает без каких-либо ошибок / предупреждений, так как 1u
является литералом типа unsigned int
который затем отрицается. Это четко определено как [Expr.unary.op] в стандартных штатах:
Отрицательное число без знака вычисляется путем вычитания его значения из 2N, где n — количество битов в повышенном операнде.
-1
однако является int
до и после отрицания и, следовательно, оно становится сужающимся обращением. Там нет отрицательных литералов; увидеть этот ответ для деталей.
По неофициальной рекламе копирование одного и того же значения в более просторное пространство, поэтому его не следует путать с размерами ( signed
а также unsigned
) равны. Даже если вы попытаетесь преобразовать его в какой-то тип большего размера, скажем, unsigned long long
это все еще сужающееся преобразование, поскольку оно не может действительно представлять отрицательное число.