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

Почему должен указываться размер перечисления при его объявлении вперед?

Я просто не понимаю, почему размер перечисления релевантен для компилятора, а размер класса - нет.

Мой пример кода:

class A;
enum E;   // must be enum E : int; in order to compile 

void f(const A & param);
void f(const E & param);

Я говорю о стандартных компиляторах С++. Я знаю, что MSVC позволяет компилировать и отлично работает. Итак, вопрос:

Почему это не стандартизировано?

4b9b3361

Ответ 1

Это стандартизировано, предложение 2764: Вперед декларация перечислений (версия 3) разрешала прямое объявление перечислений, если вы указываете базовый тип, тогда как до этого это было невозможно.

Основная причина заключается в том, что если базовый тип не указан, размер определяется реализацией и может зависеть от значений перечислителя. Из стандартного раздела проекта С++ 11 7.2 [dcl.enum]:

Для перечисления, базовый тип которого не является фиксированным, основной type является интегральным типом, который может представлять все значения счетчика определенных в перечислении. Если интегральный тип не может представлять все значения перечислителя, перечисление плохо сформировано. это определяемый реализацией, какой интегральный тип используется в качестве основного типа, за исключением того, что базовый тип не должен быть больше, чем int если значение перечислителя не может быть помещено в int или без знака внутр. Если список перечислений пуст, базовый тип выглядит так, как если бы перечисление имело единственный перечислитель со значением 0.

При передаче по значению имеет смысл, что не знать базовый тип является проблемой, но почему это проблема, когда это указатель или ссылка? Это имеет значение, поскольку, по-видимому, на некоторых архитектурах, char * и int * могут иметь разные размеры, как упоминалось в этом обсуждение comp.lang.С++: GCC и форвардная декларация перечисления:

[...] Хотя на большинстве архитектур это может быть не проблема, на некоторых архитектуры указателя будут иметь разный размер, если это char указатель. Итак, наконец, наш воображаемый компилятор понятия не имел что положить туда, чтобы получить ColorsEnum * [...]

У нас есть следующий ответ stackoverflow для ссылки, который описывает случай, когда char * может быть больше, чем int *, что подтверждает утверждение в обсуждении выше.

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

Ответ 2

Это разница в целях дизайна.

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

Неполный тип перечисления не так полезен. Однако возможность объявлять перечисление без объявления каких констант внутри этого перечисления является полезным. Сложность, возникающая из-за неполного типа перечисления, можно избежать, требуя указать размер.

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