Точка декларации для перечисления

В чем смысл объявления типов перечисления? Это сразу после названия перечисления? Я видел Standard С++ 14 (n4296) §3.3.2/3:

Точка объявления для перечисления сразу же после идентификатор (если таковой имеется) в его спецификаторе перечисления (7.2) или его первом opaque-enum-declaration (7.2), в зависимости от того, что наступит раньше.

Но когда я пытаюсь воспроизвести его,

template <class T>
struct CL
{
    using UndType = int;
};

enum class E: CL<E>::UndType;  //error: E is undefined

У меня есть ошибка для всех компиляторов, хотя enum-base для перечисления E помещается после идентификатора и должна быть видимой.

Ответы

Ответ 1

Следующее:

enum class E : CL<E>::UndType;

Не принимается как допустимое объявление в некоторых текущих реализациях (проверены clang++, g++ и MSVC). Они не принимают неполный тип E в базе enum CL<E>::UndType. Ошибка, указанная в проверенных реализациях, заключается в том, что E не указывается в этой точке. Кажется, что они помещают точку объявления в конце базы enum, они считают ее объявленной после ее завершения.

При чтении спецификаций

§14.3.1/2 Аргументы типа шаблона

[Примечание. Аргумент типа шаблона может быть неполным (3.9). - конечная нота]

И

§7.2/6 Объявления перечисления

Перечисление, базовый тип которого является фиксированным, является неполным типом из его точки объявления (3.3.2) сразу после его enum-base (если таковой имеется), после чего он становится полным.

Подчеркивает, что он компилируется; как в случае реализации CRTP.

Я уверен, что если это (т.е. неспособность скомпилировать enum class E : CL<E>::UndType;) является намерением или если оно считается прецедентом. Из спецификации в непрозрачной декларации перечисления дается некоторое "специальное" обращение w.r.t. его базовый тип и требование, чтобы он был интегральным типом.

Предположительно, код должен быть скомпилирован с учетом CWG # 1482.


Что касается текущих обходных решений...

Это

enum class E; // default underlying type is int

Является минимальным объявлением.

Прозрачная декларация может быть:

enum class E : int; // int base

Следующее будет полным определением (включая счетчики);

enum class E : int {/*...*/};

Или для использования шаблона класса можно использовать другой тип (возможно, void).

enum class E : CL<void>::UndType;