С++ 11 "перечисляемые типы" (17.5.2.1.2)

Цитата из стандарта С++ 11 (17.5.2.1.2 Перечислимые типы):

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

2 Перечислимый тип перечисления можно записать:

enum enumerated { V0 , V1 , V2 , V3 , ..... };
static const enumerated C0 (V0 );
static const enumerated C1 (V1 );
static const enumerated C2 (V2 );
static const enumerated C3 (V3 );
.....

3 Здесь имена C0, C1 и т.д. представляют собой перечисленные элементы для этого конкретного перечислимого типа. Все такие элементы имеют разные значения.

Одним из таких "перечисляемых типов" является "seekdir" из класса ios_base (27.5.3 Class ios_base):

// 27.5.3.1.5 seekdir
typedef T4 seekdir;
static constexpr fmtflags beg = unspecified ;
static constexpr fmtflags cur = unspecified ;
static constexpr fmtflags end = unspecified ;

и

27.5.3.1.5 Тип ios_base:: seekdir [ios:: seekdir]

typedef T4 seekdir;

1 Тип seekdir - это перечисляемый тип (17.5.2.1.2), который содержит элементы, указанные в таблице 126.

Итак, единственная причина, по которой эти статические константы и члены constexpr требуются, заключается в том, что "перечисляемые типы" разрешены для реализации как целочисленный тип (т.е. при перечислении int нам нужно определить константы вместо счетчиков), правильно?

Вопрос 1. Если разработчик библиотеки решает реализовать seekdir как enum, ему все равно придется определять статические константы для значений перечисления?

Вопрос 2. ПОЧЕМУ "перечисляемые типы" могут быть реализованы как целые типы в первую очередь? То есть когда реализация enum (а в С++ 11 перечисления может иметь любой основной целочисленный тип) без этих статических константных элементов может быть хуже реализации целочисленного типа?

Ответ 1

Первоначальная причина, по которой требуются объекты для значений перечислимых типов, заключается в том, что вы можете взять их адрес. Это всегда показалось мне глупым, но на ранних этапах стандартизации было довольно много переоценки.

Ответ 2

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

Для seekdir это может быть int или byte (в качестве примера), оба будут действительными представлениями. GCC имеет параметр командной строки для этого (--short-enums или -fshort-enums), по умолчанию он использовал бы int для всех enum как наименьший тип, но с опцией он использовал бы наименьший тип, который мог бы содержать все значения.

Это означает, что если реальный enum используется в сигнатуре функции, символ может измениться, и вам нужно будет перекомпилировать все. Вот почему стандарт допускает другие параметры, почему для реализации стандартной библиотеки важно контролировать этот тип, и именно поэтому ему разрешено использовать определенные целые типы.