Какой цвет установлен в соответствии со стандартом?
Ответ с цитатой из стандартов C ++ 11 и C ++ 14:
[Expr.static.cast] / 10
Значение целочисленного типа или типа перечисления может быть явно преобразовано в тип перечисления. Значение не изменяется, если исходное значение находится в диапазоне значений перечисления (7.2). В противном случае результирующее значение не определено (и может не входить в этот диапазон).
Давайте посмотрим диапазон значений перечисления : [dcl.enum] / 7
Для перечисления, базовый тип которого является фиксированным, значения перечисления являются значениями базового типа.
До CWG 1766 (C ++ 11, C ++ 14)
Следовательно, для data[0] == 100
, результирующее значение указывается (*), и не используется неопределенное поведение (UB) . В более общем смысле, когда вы преобразуете базовый тип в тип перечисления, никакое значение в не data[0]
может привести к UB для static_cast
.
После CWG 1766 (C ++ 17)
См. Дефект CWG 1766 . Абзац [expr.static.cast] p10 был усилен, так что теперь вы можете вызывать UB, если приведете значение, которое находится за пределами представимого диапазона перечисления, к типу перечисления. Это по-прежнему не относится к рассматриваемому сценарию, поскольку data[0]
относится к базовому типу перечисления (см. Выше).
Обратите внимание, что CWG 1766 считается дефектом в Стандарте, поэтому для исполнителей компилятора принято применять к своим режимам компиляции C ++ 11 и C ++ 14.
(*) char
должен иметь ширину не менее 8 бит, но не обязательно unsigned
. Максимальное хранимое значение должно быть как минимум 127
согласно Приложению E к стандарту C99.
Сравнить с [expr] / 4
Если во время вычисления выражения результат не определен математически или не находится в диапазоне представляемых значений для его типа, поведение не определено.
До CWG 1766 целочисленный тип преобразования -> тип перечисления может давать неопределенное значение . Вопрос заключается в следующем: может ли неуказанное значение находиться за пределами представимых значений для его типа? Я считаю , что ответ нет - если ответ был да , то не было бы никакой разницы в гарантии вы получаете для операций по подписанным между типами «эта операция производит неопределенное значение» и «эта операция имеет неопределенное поведение».
Следовательно, до CWG 1766, даже неstatic_cast<Color>(10000)
будет вызывать UB; но после того, как РГС 1766, он делает Invoke UB.
Теперь switch
утверждение:
[Stmt.switch] / 2
Условие должно быть целочисленного типа, типа перечисления или типа класса. [...] Интегральные продвижения выполняются.
[Conv.prom] / 4
Значение типа перечисления с незаданной областью , базовый тип которого является фиксированным (7.2), может быть преобразовано в значение базового типа. Кроме того, если интегральное продвижение может быть применено к его базовому типу, значение типа перечисления с незаданной областью, базовый тип которого является фиксированным, также может быть преобразовано в значение улучшенного базового типа.
Примечание: Основной тип Scoped перечисления без перечисления базы является int
. Для перечислений с незаданной областью базовый тип определяется реализацией, но не должен быть больше, чем int
если бы он int
мог содержать значения всех перечислителей.
Для перечисления с незаданной областью это приводит нас к / 1
Prvalue целого типа, кроме bool
, char16_t
, char32_t
или wchar_t
чье число преобразования ранга (4.13) меньше , чем ранг int
может быть преобразован в prvalue типа , int
если int
можно представить все значения типа источника; в противном случае исходное значение может быть преобразовано в тип значения unsigned int
.
В случае перечисления с незаданной областью мы будем иметь дело с int
s здесь. Для перечислений с областью действия ( enum class
и enum struct
) интегральное продвижение не применяется. В любом случае, интегральное продвижение также не приводит к UB, так как сохраненное значение находится в диапазоне базового типа и в диапазоне int
.
[Stmt.switch] / 5
Когда switch
оператор выполняется, его условие оценивается и сравнивается с каждой константой. Если одна из констант регистра равна значению условия, управление передается оператору после соответствующей case
метки. Если никакая case
константа не соответствует условию и если есть default
метка, управление переходит к оператору, помеченному default
меткой.
default
Метка должна быть хитом.
Примечание. Можно еще раз взглянуть на оператор сравнения, но он явно не используется в упомянутом «сравнении». На самом деле, нет никаких намеков на то, что в нашем случае мы введем UB для перечислений с ограниченным или незаданным объемом.
В качестве бонуса стандарт дает какие-либо гарантии как об этом, но с простым перечислением?
Независимо от того enum
, ограничена ли область действия, здесь не имеет значения. Тем не менее, имеет значение, является ли базовый тип фиксированным. Полный [decl.enum] / 7:
Для перечисления, базовый тип которого является фиксированным, значения перечисления являются значениями базового типа. В противном случае для перечисления, где e min - наименьший перечислитель, а e max - наибольшее, значения перечисления - это значения в диапазоне от b min до b max , определяемые следующим образом: Позвольте K
быть 1
для представления дополнения до двух и 0
для свое дополнение или представление величины знака. b max - наименьшее значение, большее или равное max (| e min | - K
, | e max |) и равное 2М- 1 , где M
неотрицательное целое число. b min равно нулю, если e min неотрицательно, и - (b max + K
) в противном случае.
Давайте посмотрим на следующее перечисление:
enum ColorUnfixed /* no fixed underlying type */
{
red = 0x1,
yellow = 0x2
}
Обратите внимание, что мы не можем определить это как перечисление с областью видимости, так как все перечисления с областью видимости имеют фиксированные базовые типы.
К счастью, ColorUnfixed
наименьший перечислитель есть red = 0x1
, поэтому max (| e min | - K
, | e max |) равно | e max | в любом случае, который есть yellow = 0x2
. Наименьшее значение, большее или равное 2
, равное 2 M - 1 для положительного целого числа, M
равно 3
( 2 2 - 1 ). (Я думаю, что цель состоит в том, чтобы разрешить диапазон в 1-битных шагах.) Из этого следует, что b max есть, 3
а bmin есть 0
.
Следовательно, 100
будет вне диапазона ColorUnfixed
, и static_cast
будет производить неопределенное значение до CWG 1766 и неопределенное поведение после CWG 1766.
char
, поэтому «Значение не изменяется, если исходное значение находится в диапазоне значений перечисления (7.2)». применяется.