Поведение инициализации значения перечисления

Во-первых, я хочу сказать, что, согласно cppreference.com, инициализировать перечисление несколько невозможно.

В соответствии с http://en.cppreference.com/w/cpp/language/value_initialization, Инициализация значения enum фактически выполняет инициализацию нуля. Из этого следует, что согласно http://en.cppreference.com/w/cpp/language/zero_initialization, Эффект нулевой инициализации перечисления:

Если T является скалярным типом, начальное значение объекта — это целая постоянная ноль, неявно преобразуемая в T,

Тем не менее, целочисленная константа ноль не может быть неявно преобразована в перечисление. В конечном счете, перечисление не может быть инициализировано значением. Это звучит странно, и инициализация значения enum работает на VC, GCC и Clang. Итак, что стандарт говорит об этом?

Во-вторых, согласно http://en.cppreference.com/w/cpp/language/static_cast:

Целочисленный тип, тип с плавающей точкой или тип перечисления может быть преобразован в любой полный тип перечисления (результат не определен (до C ++ 17), неопределенное поведение (начиная с C ++ 17), если значение выражения преобразовано в базовый тип перечисления , не является одним из целевых значений перечисления)

Итак, означает ли это, что инициализация значения перечисления (если оно вообще работает) может фактически привести к неопределенному поведению, если целевое перечисление не имеет перечислителя, равного 0?

30

Решение

Ответ на это был дан в комментариях. Моя попытка объяснить весь стандарт за этим дана ниже.

к нулевой инициализации объект или ссылка типа T средства:

  • если T является скалярным типом (3.9), объект инициализируется значением
    получается путем преобразования целочисленного литерала 0 (ноль) до T;

(Перечисления являются скалярными типами; §3.9 / 9)
Так как преобразование не называется неявным, мы не смотрим в §4, а в §5.2.9;

Результат выражения static_cast<T>(v) является результатом
преобразование выражения v печатать T,

Затем в §5.2.9 / 10 определяется, как целочисленные значения преобразуются в типы перечисления.

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

Должно быть показано, что ноль находится в диапазоне значений перечисления для всех перечислений.
Следующие пять цитат взяты из §7.2 / 8:

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

Поскольку все разрешенные базовые типы включают ноль в свой диапазон значений *, это автоматически дает желаемый результат. Теперь для перечислений без фиксированных базовых типов,

В противном случае для перечисления, где емин самый маленький
счетчик и е Максимум является наибольшим, значения
перечисление значения в диапазоне б мин в б
Максимум
, определяется следующим образом:

То есть мы должны показать, что бмин всегда меньше или равно нулю, и бМаксимум всегда больше или равно нулю.

Позволять К быть 1 для двоих
дополнение представления и 0 для дополнения или
представление величины знака.
б Максимум наименьшее значение больше или равно тах (| е мин| — К, | е Максимум|) и равно 2М — 1, где
M неотрицательное целое число

| е Максимум| является неотрицательным, и максимум двух чисел, по крайней мере, так же велик, как оба числа. следовательно тах (| е мин| — К, | е Максимум|) также неотрицателен, и бМаксимум должно быть больше или равно этому числу — поэтому наше первое требование выполнено.

б мин ноль, если емин неотрицателен и — (бМаксимум + K) иначе.

бмин явно либо ноль, либо отрицательный: бМаксимум является неотрицательным, как показано выше, и К неотрицательно (0 или 1), следовательно, аддитивная обратная их сумма не положительна. Наше второе требование выполнено. В заключение,

Если переписчик-лист пусто, значения
перечисления, как если бы перечисление имел один перечислитель с
значение 0,

Это приводит к приведенному выше результату путем установки емин = еМаксимум = 0.


  • Это сводится к утверждению «Все целочисленные типы имеют ноль в диапазоне значений», что остается доказать читателю.
3

Другие решения

1: Это можно понять так:

enum class SomeEnum : int { V1 = 0, V2 = 1, V3 = 2 };
SomeEnum a = 0; // compile error
SomeEnum b = SomeEnum.V1; // OK

Это базовая защита от неопределенного поведения!

2: Да и Да 🙂

SomeEnum c = static_cast<SomeEnum>(1); // = SomeEnum.V2
SomeEnum d = static_cast<SomeEnum>(5); // undefined behavior

static_cast опасен по определению, его следует использовать только для поддержки сериализации или старых интерфейсов c!

2

По вопросам рекламы [email protected]