Подтвердить что ты не робот

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

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

Согласно 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:

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

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

4b9b3361

Ответ 1

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

Для нулевой инициализации объекта или ссылки типа 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:

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

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

В противном случае для перечисления, где e min является наименьшим перечислитель и e max является наибольшим, значения перечисление - это значения в диапазоне b min до b max, определяемый следующим образом:

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

Пусть K равно 1 для двух дополнение и 0 для одного дополнения или представление знаковой величины.
b max - наименьшее значение, большее или равное max (| e min | - K, | e max |) и равна 2M - 1, где M - неотрицательное целое число.

| e max | неотрицательна, а максимум двух чисел не меньше, чем оба числа. Следовательно, max (| e min | - K, | e max |) также неотрицателен, а b max должен быть больше или равное этому числу, поэтому наше первое требование выполнено.

b min равно нулю, если e min неотрицательно и - (b max + K) в противном случае.

b min явно либо ноль, либо отрицательный: b max неотрицателен, как показано выше, и K неотрицательно (0 или 1), следовательно, аддитивная обратная их сумма неположительна. Наше второе требование выполнено. Наконец,

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

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


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

Ответ 2

1: Это может быть недопустимо:

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

Это основная защита от поведения undefined!

2: Да и Да:)

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

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