Я расскажу о проблеме с правилами в черновом варианте стандарта ISO CPP "Неправильный и неполный" n4659 . Акцент добавлен мной.
11.3.4 определяет объявления массива. Первый абзац содержит
Если присутствует константное выражение [в квадратных скобках] (8.20), оно должно быть преобразованным константным выражением типа std :: size_t [...].
std::size_t
от <cstddef>
и определяется как
[...] определяемый реализацией целочисленный тип без знака, достаточно большой, чтобы содержать размер в байтах любого объекта.
Поскольку он импортируется через заголовки стандартной библиотеки C, стандарт C имеет отношение к свойствам size_t
. Проект ISO C N2176 предписывает в 7.20.3 "минимальные максимумы", если хотите, целочисленных типов. Для size_t
этот максимум составляет 65535. Другими словами, 16-битный size_t
полностью соответствует.
«Преобразованное константное выражение» определено в 8.20 / 4:
A преобразованное константное выражение типа T является выражением, неявно преобразованным в тип T, где преобразованное выражение является константным выражением, а последовательность неявного преобразования содержит только [любое из 10 различных преобразований, одно из что касается целых чисел (пар. 4.7):]
- интегральные преобразования (7,8) , кроме сужающих преобразований (11.6.4)
Интегральное преобразование (в отличие от повышения , которое изменяет тип на эквивалентные или более крупные типы) определяется следующим образом (7.8 / 3):
Значение типа целого можно преобразовать в значение другого целого типа.
7,8 / 5 затем исключает интегральные повышения из интегральных преобразований. Это означает, что преобразования обычно сужают изменения типа .
Сужающие преобразования (которые, как вы помните, исключены из списка разрешенных преобразований в преобразованных константных выражениях , используемых для размеров массивов), определяются в контексте списка -инициализация, 11.6.4, пар. 7
Сужающее преобразование - это неявное преобразование
[...]
7.3 1 - от целочисленного типа [...] до целочисленного типа, который не может представлять все значения исходного типа, за исключением случаев, когда источником является константное выражение, значение которого после целочисленных повышений будет вписывается в целевой тип.
Это фактически говорит о том, что эффективный размер массива должен быть постоянным значением при отображении, что является вполне разумным требованием для избежания неожиданностей.
Теперь давайте все вместе поковыряем. Рабочая гипотеза состоит в том, что
std::size_t
является 16-разрядным целочисленным типом без знака со значением в диапазоне 0,65535. Целочисленный литерал
65537
не представлен в 16-битном системном
unsigned int
и, следовательно, имеет тип
long
. Поэтому он будет подвергаться
целочисленному преобразованию. Это будет
сужающее преобразование , поскольку значение не может быть представлено в 16-битном
size_t
2 , так что условие исключения в 11.6.4 / 7.3, «значение подходит в любом случае», не применяется.
Так что это значит?
11.6.4 / 3.11 - это правило всеохвата для сбоя при создании значения инициализатора из элемента в списке инициализатора. Поскольку правила списков инициализаторов используются для размеров массивов, мы можем предположить, что универсальное условие сбоя преобразования применяется к константе размера массива:
(3.11) - в противном случае программа будет некорректной.
Для выполнения диагностики требуется соответствующий компилятор. Дело закрыто.
1 Да, они подразделяют пункты.
2 Преобразование целочисленного значения 65537 (в любом типе, который может содержать число & mdash; здесь, вероятно, `long) в 16-битовое целое число без знака является определенной операцией. 7,8 / 2 детали:
Если тип назначения является беззнаковым, полученное значение является наименее целым числом без знака, соответствующим исходному
целое число (по модулю 2 n , где n - количество битов, используемых для представления типа без знака). [Примечание: в двух
дополняющее представление, это преобразование является концептуальным, и в битовой комбинации нет изменений (если есть
без усечения). —Конечная записка]
Двоичное представление 65537 равно 1_0000_0000_0000_0001
, т. Е. Устанавливается только младший значащий бит из младших 16 бит. Преобразование в 16-битное значение без знака (которое указывает косвенное свидетельство size_t
is) вычисляет [значение выражения] по модулю 2 ^ 16, то есть просто принимает младшие 16 бит. Это приводит к значению 1, указанному в диагностике компилятора.