Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Перечисление — это определяемый пользователем тип, состоящий из набора именованных целочисленных констант, которые называются перечислителями.
Замечание
В этой статье рассматриваются тип языка enum C++ стандарта ISO и тип ограниченного (или строго типизированного), enum class который представлен в C++11. Сведения о public enum class типах private enum class или типах в C++/CLI и C++/CX см. в статьях enum class (C++/CLI и C++/CX).
Синтаксис
enum-name:
identifier
enum-specifier:
enum-head
{
enumerator-list
выбирать}
enum-head
{
enumerator-list
,
}
enum-head:
enum-key
attribute-specifier-seq
выбиратьenum-head-nameвыбиратьenum-baseвыбирать
enum-head-name:
nested-name-specifier
выбиратьidentifier
opaque-enum-declaration:
enum-key
attribute-specifier-seq
выбиратьenum-head-nameenum-baseвыбирать;
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-seq
выбирать
Использование
// unscoped enum:
// enum [identifier] [: type] {enum-list};
// scoped enum:
// enum [class|struct] [identifier] [: type] {enum-list};
// Forward declaration of enumerations (C++11):
enum A : int; // non-scoped enum must have type specified
enum class B; // scoped enum defaults to int but ...
enum class C : short; // ... may have any integral underlying type
Параметры
identifier
Имя типа, заданное перечислению.
type
Базовый тип перечислителей; Все перечислители имеют одинаковый базовый тип. Может быть любым целочисленным типом.
enum-list
Разделенный запятыми список перечислителей в перечислении. Каждый перечислитель или имя переменной в области должен быть уникальным. Однако значения можно дублировать. В неуправляемом перечислении область — это окружающая область; в перечислении с заданной областью область сама по себе enum-list . В перечислении в области список может быть пустым, который фактически определяет новый целочисленный тип.
class
Используя это ключевое слово в объявлении, вы указываете область перечисления, и identifier необходимо указать ее. Вы также можете использовать ключевое struct слово вместо classсемантически эквивалентного в этом контексте.
Область перечислителя
Перечисление предоставляет контекст для описания диапазона значений, представленных как именованные константы. Эти именованные константы также называются перечислителями. В исходных типах C и C++ enum перечислители неквалифицируются во всей области, в которой объявлен.enum В ограниченных перечислениях имя перечислителя должно быть квалифицировано по enum имени типа. В следующем примере показано основное различие между двумя типами перечислений:
namespace CardGame_Scoped
{
enum class Suit { Diamonds, Hearts, Clubs, Spades };
void PlayCard(Suit suit)
{
if (suit == Suit::Clubs) // Enumerator must be qualified by enum type
{ /*...*/}
}
}
namespace CardGame_NonScoped
{
enum Suit { Diamonds, Hearts, Clubs, Spades };
void PlayCard(Suit suit)
{
if (suit == Clubs) // Enumerator is visible without qualification
{ /*...*/
}
}
}
Каждое имя перечисления присваивается целочисленное значение, соответствующее его месту в порядке значений перечисления. По умолчанию первое значение присваивается 0, следующее присваивается 1 и т. д., но можно явно задать значение перечислителя, как показано ниже:
enum Suit { Diamonds = 1, Hearts, Clubs, Spades };
Перечислитель Diamonds назначается значение 1. Последующие перечислители, если они не имеют явного значения, получают значение предыдущего перечислителя плюс один. В предыдущем примере Hearts будет иметь значение 2, Clubs будет иметь 3 и т. д.
Каждый перечислитель обрабатывается как константа и должен иметь уникальное имя в области, в которой enum определено (для неуправляемых перечислений) или внутри enum себя (для перечисления в области). Значения, заданные именам, не должны быть уникальными. Например, рассмотрим это объявление неуправляемой перечисления Suit:
enum Suit { Diamonds = 5, Hearts, Clubs = 4, Spades };
Значения Diamonds, HeartsClubsи Spades имеют значение 5, 6, 4 и 5 соответственно. Обратите внимание, что 5 используется более одного раза; Это разрешено, даже если оно не может быть предназначено. Эти правила одинаковы для перечислений в области.
Приведение правил
Неявно преобразуемые intконстанты перечисления могут быть неявно преобразованы, но int неявно преобразуется в значение перечисления. В следующем примере показано, что происходит при попытке назначить hand значение, которое не Suitявляется:
int account_num = 135692;
Suit hand;
hand = account_num; // error C2440: '=' : cannot convert from 'int' to 'Suit'
Приведение требуется для преобразования int в область действия или неуправляемого перечислителя. Однако вы можете повысить уровень перечисления без приведения к целочисленным значениям.
int account_num = Hearts; //OK if Hearts is in an unscoped enum
Использование неявных преобразований таким образом может привести к непреднамеренных побочных эффектов. Чтобы устранить ошибки программирования, связанные с неуправляемыми перечислениями, строго типизированные значения перечисления в области. Перечислители с ограниченной областью должны быть квалифицированы именем типа перечисления (идентификатором) и не могут быть неявно преобразованы, как показано в следующем примере:
namespace ScopedEnumConversions
{
enum class Suit { Diamonds, Hearts, Clubs, Spades };
void AttemptConversions()
{
Suit hand;
hand = Clubs; // error C2065: 'Clubs' : undeclared identifier
hand = Suit::Clubs; //Correct.
int account_num = 135692;
hand = account_num; // error C2440: '=' : cannot convert from 'int' to 'Suit'
hand = static_cast<Suit>(account_num); // OK, but probably a bug!!!
account_num = Suit::Hearts; // error C2440: '=' : cannot convert from 'Suit' to 'int'
account_num = static_cast<int>(Suit::Hearts); // OK
}
}
Обратите внимание, что строка hand = account_num; по-прежнему вызывает ошибку, которая возникает с неуправляемыми перечислениями, как показано ранее. Допускается явное приведение. Однако при использовании ограниченных перечислений попытка преобразования в следующей инструкции account_num = Suit::Hearts;больше не допускается без явного приведения.
Перечисления без перечислителей
Visual Studio 2017 версии 15.3 и более поздних версий (доступных /std:c++17 и более поздних версий): определив перечисление (обычный или ограниченный) с явным базовым типом и без перечислителей, вы можете в действительности ввести новый целочисленный тип, который не имеет неявного преобразования в любой другой тип. Используя этот тип вместо встроенного базового типа, можно исключить вероятность тонких ошибок, вызванных непреднамеренно неявными преобразованиями.
enum class byte : unsigned char { };
Новый тип представляет собой точную копию базового типа и, следовательно, имеет то же соглашение о вызовах, что означает, что его можно использовать в ABIs без каких-либо штрафов за производительность. При инициализации переменных типа не требуется приведение с помощью инициализации прямого списка. В следующем примере показано, как инициализировать перечисления без перечислителей в различных контекстах:
enum class byte : unsigned char { };
enum class E : int { };
E e1{ 0 };
E e2 = E{ 0 };
struct X
{
E e{ 0 };
X() : e{ 0 } { }
};
E* p = new E{ 0 };
void f(E e) {};
int main()
{
f(E{ 0 });
byte i{ 42 };
byte j = byte{ 42 };
// unsigned char c = j; // C2440: 'initializing': cannot convert from 'byte' to 'unsigned char'
return 0;
}