Что произойдет, если значение static_cast недопустимо для classа enum?

Рассмотрим этот код C ++ 11:

enum class Color : char { red = 0x1, yellow = 0x2 } // ... char *data = ReadFile(); Color color = static_cast(data[0]); 

Предположим, что данные [0] на самом деле 100. Что такое цвет, установленный в соответствии со стандартом? В частности, если я позже сделаю

 switch (color) { // ... red and yellow cases omitted default: // handle error break; } 

Стандарт гарантирует, что по умолчанию будет удалено? Если нет, то какой правильный, самый эффективный, самый элегантный способ проверить ошибку здесь?

РЕДАКТИРОВАТЬ:

В качестве бонуса, делает ли стандарт какие-либо гарантии по этому поводу, но с простым перечислением?

Что такое цвет в соответствии со стандартом?

Ответ с цитатой из C ++ 11 и C ++ 14:

[Expr.static.cast] / 10

Значение интегрального или перечисляемого типа может быть явно преобразовано в тип enums. Значение не изменяется, если исходное значение находится в диапазоне значений enums (7.2). В противном случае результирующее значение не указано (и может быть не в этом диапазоне).

Давайте посмотрим на диапазон значений enums : [dcl.enum] / 7

Для enums, базовый тип которого фиксирован, значения enums являются значениями базового типа.

Перед CWG 1766 (C ++ 11, C ++ 14) Поэтому для data[0] == 100 результирующее значение указано (*), и не задействовано Undefined Behavior (UB) . В более общем плане, когда вы отбрасываете базовый тип в тип enums, никакое значение в data[0] может привести к UB для static_cast .

После CWG 1766 (C ++ 17) См. Дефект CWG 1766 . Параграф [expr.static.cast] p10 был усилен, поэтому теперь вы можете вызывать UB, если вы выставляете значение, выходящее за пределы отображаемого диапазона enums, в тип enums. Это все еще не относится к сценарию в вопросе, поскольку data[0] относятся к базовому типу enums (см. Выше).

Обратите внимание, что CWG 1766 считается дефектом Стандарта, поэтому для разработчиков компилятора принято применять их в режимах компиляции C ++ 11 и C ++ 14.

(*) char должен иметь ширину не менее 8 бит, но не обязательно быть unsigned . Максимально допустимое значение хранения должно быть не менее 127 в приложении E стандарта C99.


Сравнить с [expr] / 4

Если во время оценки выражения результат не определяется математически или нет в диапазоне представляемых значений для его типа, поведение не определено.

До CWG 1766 тип типа интегрального преобразования -> перечисляет неопределенное значение . Возникает вопрос: может ли неопределенное значение быть вне отображаемых значений для его типа? Я считаю, что ответ отрицательный: если бы ответ был да , не было бы никакой разницы в гарантиях, которые вы получаете для операций над подписанными типами, между «эта операция производит неопределенное значение» и «эта операция имеет неопределенное поведение».

Следовательно, до CWG 1766 даже static_cast(10000) не будет вызывать UB; но после CWG 1766 он вызывает UB.


Теперь оператор switch :

[Stmt.switch] / 2

Условие должно быть целочисленного типа, типа enums или типа classа. […] Выполняются интегральные рекламные акции.

[Conv.prom] / 4

Присвоение неперечисленного типа enums, базовый тип которого является фиксированным (7.2), может быть преобразовано в prvalue его базового типа. Более того, если интегральное продвижение может быть применено к его базовому типу, может быть преобразовано значение classа неперечисленного enums, базовый тип которого может быть преобразован в prvalue продвинутого базового типа.

Примечание. Тип базового типа с перечислением enum без enum-baseint . Для незанятых перечислений базовый тип определяется реализацией, но не должен быть больше, чем int если int может содержать значения всех счетчиков.

Для неперечисленного enums это приводит к тому, что / 1

PRvalue целочисленного типа, отличного от bool , char16_t , char32_t или wchar_t чей целочисленный ранг преобразования (4.13) меньше ранга int может быть преобразован в prvalue типа int если int может представлять все значения типа источника ; в противном случае исходное значение prvalue может быть преобразовано в prvalue типа unsigned int .

В случае неперечисленного enums мы будем иметь дело с int s здесь. Для облачных перечислений ( enum class и enum struct ) не применяется интегральная продвижение. В любом случае интегральное продвижение не приводит к UB, поскольку сохраненное значение находится в диапазоне базового типа и в диапазоне от int .

[Stmt.switch] / 5

Когда оператор switch выполняется, его состояние оценивается и сравнивается с каждой константой случая. Если одна из констант случая равна значению условия, управление передается в оператор, следующий за меткой совпадающего кода. Если константа события не совпадает с условием, и если есть метка по default , управление переходит к оператору, помеченному меткой по default .

Метка по default должна быть удалена.

Примечание. Можно было бы еще раз взглянуть на оператор сравнения, но он явно не используется в упомянутом «сравнении». На самом деле, нет никакого намека на то, что в нашем случае мы представим UB для облачных или неперечисленных перечислений.


В качестве бонуса, делает ли стандарт какие-либо гарантии по этому поводу, но с простым перечислением?

Независимо от того, enum ли enum здесь нет никакой разницы. Однако имеет значение, является ли основной тип фиксированным. Полный [decl.enum] / 7:

Для enums, базовый тип которого фиксирован, значения enums являются значениями базового типа. В противном случае для enums, где e min является наименьшим перечислителем, а e max является наибольшим, значения enums представляют собой значения в диапазоне от b min до b max , определяемые следующим образом: пусть K равно 1 для представления двух дополнений и 0 для представления своего дополнения или знака. b max – наименьшее значение, большее или равное max (| e min | – K , | e max |) и равно 2 M – 1 , где M – неотрицательное целое число. b min равно нулю, если e min неотрицательно и – (b max + K ) в противном случае.

Давайте посмотрим на следующее перечисление:

 enum ColorUnfixed /* no fixed underlying type */ { red = 0x1, yellow = 0x2 } 

Обратите внимание, что мы не можем определить это как перечислимое перечисление, так как все скопированные enums имеют фиксированные базовые типы.

К счастью, ColorUnfixed маленький перечислитель 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.

  • Когда использовать std :: begin и std :: end вместо контейнеров конкретных версий
  • Enum vs Сильно типизированное перечисление
  • Самый простой и аккуратный c ++ 11 ScopeGuard
  • Что делает этот код вариационного шаблона?
  • Перегруженные lambdas в C ++ и различия между clang и gcc
  • Как включить C ++ 11 в Qt Creator?
  • Генерация случайных чисел в C ++ 11, как сгенерировать, как они работают?
  • Специализация шаблонов псевдонимов
  • May std :: vector использует небольшую оптимизацию буфера?
  • Что стандартная библиотека гарантирует самопереключение?
  • Может ли код C ++ быть действительным как в C ++ 03, так и в C ++ 11, но делать разные вещи?
  • Давайте будем гением компьютера.