Какой цвет установлен в соответствии со стандартом?
Ответ с цитатой из стандартов 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.
В случае перечисления с незаданной областью мы будем иметь дело с ints здесь. Для перечислений с областью действия ( 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)». применяется.