10 Declarations [dcl.dcl]

10.2 Enumeration declarations [dcl.enum]

Перечисление - это отдельный тип ([basic.compound]) с именованными константами. Его имя становится enum-nameвнутри его объема.

enum-name:
	identifier
enum-specifier:
	enum-head { enumerator-listopt }
	enum-head { enumerator-list , }
enum-head:
	enum-key attribute-specifier-seqopt enum-head-nameopt enum-baseopt
enum-head-name:
	nested-name-specifieropt identifier
opaque-enum-declaration:
	enum-key attribute-specifier-seqopt nested-name-specifieropt identifier enum-baseopt ;
enum-key:
	enum
	enum class
	enum struct
enum-base:
	: type-specifier-seq
enumerator-list:
	enumerator-definition
	enumerator-list , enumerator-definition
enumerator-definition:
	enumerator
	enumerator = constant-expression
enumerator:
	identifier attribute-specifier-seqopt

Необязательное attribute-specifier-seqв enum-headи opaque-enum-declarationпринадлежит перечислению; атрибуты в нем attribute-specifier-seqвпоследствии считаются атрибутами перечисления, когда бы оно ни было названо.: Следующий « » в пределах от обрабатываются как часть . [ Это устраняет потенциальную двусмысленность между объявлением перечисления с помощью и объявлением безымянного битового поля перечислимого типа. [enum nested-name-specifieropt identifierdecl-specifier-seqmember-declarationenum-baseNote: enum-baseExample:

   struct S {
     enum E : int {};
     enum E : int {};           // error: redeclaration of enumeration
   };

end example] ] Если содержит , то декларация должна быть .end noteopaque-enum-declarationnested-name-specifierexplicit specialization

Тип перечисления, объявленный с помощью enum-key of only,enum - это anunscoped enumeration, а его enumerators areunscoped enumerators. Операторы enum-keysenum class и enum struct семантически эквивалентны; тип перечисления объявляются с одним из них являетсяscoped enumeration, и ее enumerators являютсяscoped enumerators. Необязательный параметр identifierне может быть опущен в объявлении перечисления с ограниченным объемом. Объект type-specifier-seqan enum-base должен называть целочисленный тип; любая CV-квалификация игнорируется. Объявление opaque-enum-declarationперечисления без области действия не должно пропускать enum-base. Идентификаторы в объекте enumerator-listобъявлены как константы и могут появляться везде, где требуются константы. Символ enumerator-definitionс= дает связанное enumeratorзначение, указанное с помощью constant-expression. Если у первого enumerator нет initializer, значение соответствующей константы равно нулю. Знак enumerator-definitionбез знака initializerдает enumeratorзначение, полученное путем увеличения значения предыдущего enumerator на единицу. [Example:

enum { a, b, c=0 };
enum { d, e, f=e+2 };

определяетa,cиd быть нулем,b и e быть1, иf быть3. ] Необязательный в входит в этот счетчику.end exampleattribute-specifier-seqenumerator

An opaque-enum-declarationявляется либо повторным объявлением перечисления в текущей области, либо объявлением нового перечисления. [ Note: Перечисление, объявленное объектом, opaque-enum-declarationимеет фиксированный базовый тип и является полным типом. Список счетчиков может быть предоставлен позже при повторном объявлении с расширением enum-specifier. ] Перечисление с ограниченной областью действия не должно позже повторно объявляться как не имеющее области действия или с другим базовым типом. Перечисление с незаданной областью не должно позже повторно объявляться как ограниченное, и каждое повторное объявление должно включать указание того же базового типа, что и в исходном объявлении.end noteenum-base

Если за enum-keyсимволом следует a nested-name-specifier, то enum-specifierдолжен ссылаться на перечисление, которое ранее было объявлено непосредственно в классе или пространстве имен, на которое nested-name-specifierссылается (т. Е. Не унаследовано и не введено a using-declaration), и enum-specifierдолжно появиться в пространстве имен, включающем предыдущее объявление.

Каждое перечисление определяет тип, отличный от всех других типов. Каждое перечисление также имеетunderlying type. Базовый тип можно явно указать с помощью enum-base. Для типа перечисления с ограниченной областью действия базовый тип -int это если он не указан явно. В обоих случаях говорят, что основным типом является fixed. После закрывающей фигурной скобки у enum-specifierкаждого перечислителя указан тип его перечисления. Если базовый тип фиксирован, тип каждого перечислителя перед закрывающей фигурной скобкой является базовым типом, а constant-expressionв enumerator-definition должен быть converted constant expression базовым типом. Если базовый тип не фиксирован, тип каждого перечислителя перед закрывающей фигурной скобкой определяется следующим образом:

  • Если для перечислителя указан инициализатор, то constant-expressionдолжен быть integral constant expression. Если выражение имеет тип перечисления с незаданной областью, перечислитель имеет базовый тип этого типа перечисления, в противном случае он имеет тот же тип, что и выражение.

  • Если для первого перечислителя не указан инициализатор, его тип является неопределенным целочисленным типом со знаком.

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

Перечисление, базовый тип которого фиксирован, является неполным типом от его point of declaration до сразу после него enum-base(если есть), и в этот момент оно становится полным типом. Перечисление базовый тип которого не фиксируется неполный тип с его точки к декларации сразу же после закрытия} из ее enum-specifier, и в этот момент он становится полным типа.

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

Для перечисления, базовый тип которого фиксирован, значения перечисления являются значениями базового типа. В противном случае, для перечисления, гдеemin наименьший перечислитель и emax наибольший, значения перечисления - это значения в диапазонеbmin доbmax, определяемом следующим образом: ПустьK будет 1 для представления с дополнением до двух и 0 для дополнения до единиц или знака - представление величины.bmax - наименьшее значение, большее или равноеmax(|emin|K,|emax|) и равное 2M1, гдеM - неотрицательное целое число.bmin равно нулю, если emin неотрицательно, и в(bmax+K) противном случае. Размер самого маленького битового поля достаточно большой , чтобы вместить все значения типа перечисление ,max(M,1) еслиbmin равен нулю , а вM+1 противном случае. Можно определить перечисление, значения которого не определены ни одним из его перечислителей. Если enumerator-listпусто, значения перечисления такие, как если бы перечисление имело единственный перечислитель со значением 0.96

Два типа перечисления - этоlayout-compatible enumerations если они имеют один и тот же базовый тип.

Значение перечислителя или объекта перечислимого типа с незаданной областью преобразуется в целое число с помощьюintegral promotion. [Example:

  enum color { red, yellow, green=20, blue };
  color col = red;
  color* cp = &col;
  if (*cp == blue)              // ...

создаетcolor тип, описывающий различные цвета, а затем объявляет col как объект этого типа иcp как указатель на объект этого типа. Возможные значения объекта типа color являютсяred,yellow,green, blue; эти значения могут быть преобразованы в целые значения 0,1,20и21. Поскольку перечисления относятся к разным типам, объектам типаcolor могут быть присвоены только значения типаcolor.

color c = 1;                    // error: type mismatch, no conversion from int to color
int i = yellow;                 // OK: yellow converted to integral value 1, integral promotion

Обратите внимание , что это неявныйenum дляint преобразования не предусмотрен для контекстного перечисления:

enum class Col { red, yellow, green };
int x = Col::red;               // error: no Col to int conversion
Col y = Col::red;
if (y) { }                      // error: no Col to bool conversion

end example]

Все без enum-nameисключения объекты с незаданной областью enumeratorобъявляются в области, которая непосредственно содержит enum-specifier. Каждая область видимости enumeratorобъявляется в области действия перечисления. Эти имена подчиняются правилам области видимости, определенным для всех имен в[basic.scope] и[basic.lookup]. [Example:

enum direction { left='l', right='r' };

void g()  {
  direction d;                  // OK
  d = left;                     // OK
  d = direction::right;         // OK
}

enum class altitude { high='h', low='l' };

void h()  {
  altitude a;                   // OK
  a = high;                     // error: high not in scope
  a = altitude::low;            // OK
}

end example] На перечислитель, объявленный в области класса, можно ссылаться с помощью операторов доступа к членам класса (​::​,. (точка) и-> (стрелка)), см[expr.ref]. [Example:

struct X {
  enum direction { left='l', right='r' };
  int f(int i) { return i==left ? 0 : i==right ? 1 : 2; }
};

void g(X* p) {
  direction d;                  // error: direction not in scope
  int i;
  i = p->f(left);               // error: left not in scope
  i = p->f(X::right);           // OK
  i = p->f(p->left);            // OK
  // ...
}

end example]

Если an enum-headсодержит a nested-name-specifier, то enum-specifierдолжен ссылаться на перечисление, которое ранее было объявлено непосредственно в классе или пространстве имен, на которое nested-name-specifierссылается, или в элементе встроенного пространства имен set ([namespace.def]) этого пространства имен (т. Е. Не просто унаследовано или введено using-declaration), и enum-specifierдолжен появиться в пространстве имен, включающем предыдущее объявление. В таких случаях nested-name-specifier из enum-headопределения не должно начинаться с decltype-specifier.

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