Ответ 1
Это очень интересный вопрос. Простой ответ заключается в том, что это буквально undefined: стандарт ничего не говорит об этом случае.
Чтобы иметь лучший пример, рассмотрим этот enum
:
enum foo : bool { True=true, undefined };
В соответствии со стандартом:
[dcl.enum]/2: [...] Определение перечислителя без инициализатора дает перечислителю значение, полученное путем увеличения значения предыдущего перечислителя на единицу.
Следовательно, значение foo::undefined
в нашем примере равно 2
(true+1
). Который не может быть представлен как bool
.
Он плохо сформирован?
Нет, в соответствии со стандартом, это совершенно верно, только нефиксированный базовый тип имеет ограничение на невозможность представления всех значений счетчика:
[dcl.enum]/7: для перечисления, основной тип которого не фиксирован, [...] Если интегральный тип не может представлять все значения счетчика, перечисление плохо сформировано.
В нем ничего не говорится о фиксированном базовом типе, который не может представлять все значения счетчика.
Каково значение исходного вопроса oops
и undefined
?
Это undefined: стандарт ничего не говорит об этом случае.
Возможные значения для foo::undefined
:
- Максимальное возможное значение (
true
):undefined
иoops
должно быть максимальным значением базового типа. - Наименьшее возможное значение (
false
): минимальное значение базового типа. Примечание. В целых числах со знаком это не будет соответствовать текущему поведению для переполнения Integer (undefined). - Случайное значение (?): компилятор выберет значение.
Проблема со всеми этими значениями состоит в том, что она может привести к двум полям с одинаковым значением (например, foo::True == foo::undefined
).
Разница между инициализатором (например, undefined=2
) и "неявным" инициализатором (например, True=true, undefined
)
В соответствии со стандартом:
[dcl.enum]/5: Если базовый тип является фиксированным, тип каждого перечислителя перед замыкающей скобкой является базовым типом, а константное выражение в определении перечисления должно быть преобразованным постоянным выражением базовый тип.
Другими словами:
enum bar : bool { undefined=2 };
эквивалентно
enum bar : bool { undefined=static_cast<bool>(2) };
И тогда bar::undefined
будет true
. В "неявном" инициализаторе это не так: этот стандартный параграф говорит об этом только инициализаторе, а не о "неявном" инициализаторе.
Резюме
- Таким образом, возможно, что
enum
с фиксированным базовым типом имеют недопредставленные значения. - Их значение undefined по стандарту.
В соответствии с вопросом и комментариями это недействительно в GCC и clang, но актуально для MSVS-2015 (с предупреждением).