Класс enum (C++/CLI и C++/CX)
Объявляет перечисление в области видимости пространства имен, которое является определяемым пользователем типом, состоящим из ряда именованных констант, называемых перечислителями.
Все среды выполнения
Комментарии
C++/CX и C++/CLI поддерживают открытый класс перечисления и закрытый класс перечисления, которые схожи со стандартным классом перечисления C++, но с добавлением спецификатора доступа. В /CLR тип класса перечисления C++11 разрешен, но будет создавать предупреждение C4472, предназначенное для того, чтобы убедиться, что вам действительно требуется тип перечисления стандарта ISO, а не типы C++/CX или C++/CLI. Дополнительные сведения о ключевое слово стандарта ISO C++ enum см. в разделе Перечисления.
Среда выполнения Windows
Синтаксис
access enum class enumeration-identifier [:underlying-type] < enumerator-list >[var]; accessenum structenumeration-identifier[:underlying-type] < enumerator-list >[var];
Параметры
Доступа
Уровень доступа перечисления, который может иметь значение public или private .
enumeration-identifier
Имя перечисления.
Базовый тип
(Необязательно) Базовый тип перечисления.
(Необязательно. Только среда выполнения Windows) Базовый тип перечисления, который может быть , , , , , , int , uint32 , int64 или uint64 . uint16 int16 char16 char bool
перечислитель-список
Разделенный запятыми список имен перечислителей.
Значение каждого перечислителя является константным выражением, которое определяется либо неявно компилятором, либо явно с помощью нотации перечислителя = constant-expression. По умолчанию значение первого перечислителя ноль, если он определен неявно. Значение каждого следующего неявно определенного перечислителя — значение предыдущего перечислителя + 1.
var
(Необязательно) Имя переменной типа перечисления.
Комментарии
Дополнительные сведения и примеры см. в разделе Перечисления.
Обратите внимание, что компилятор выводит сообщения об ошибках, если константное выражение, задающее значение перечислителя, не может быть представлено underlying-type. Однако компилятор не сообщает об ошибке для значения, недопустимого для базового типа. Пример:
- Если базовый тип является числовым, а перечислитель задает максимальное значение для этого типа, значение следующего неявно определенного перечисления не может быть представлено.
- Если underlying-type является bool и более двух перечислителей определены неявно, то нельзя представить перечислители после первых двух.
- Если underlying-type является char16 и значение перечисления в диапазоне от 0xD800 до 0xDFFF, то значение можно представить. Однако логически значение неверно, так как оно представляет половину пары символов-заместителей Юникода и не должно отображаться в изоляции.
Требования
Среда CLR
Синтаксис
access enum class name [:type] < enumerator-list >var; accessenum structname [:type] < enumerator-list >var;
Параметры
Доступа
Уровень доступа перечисления. Может быть либо public , либо private .
перечислитель-список
Разделенный запятыми список идентификаторов (перечислителей) в перечислении.
name
Имя перечисления. Анонимные управляемые перечисления не допускаются.
type
(Необязательно) Базовый тип identifiers. Это может быть любой скалярный тип, например подписанные или неподписанные int версии , short или long . bool или char также допустимы.
var
(Необязательно) Имя переменной типа перечисления.
Комментарии
enum class и enum struct являются эквивалентными объявлениями.
Существуют два типа перечислений: управляемые (C++/CX) и стандартные.
Управляемые перечисления (или перечисления C++/CX) могут быть определены следующим образом:
Это семантически эквивалентно:
Стандартное перечисление может быть определено следующим образом:
Это семантически эквивалентно:
static const int sun = 0; static const int mon = 1;
Управляемые имена перечислителей (identifiers) не вводятся в область, в которой определяется перечисление; все ссылки на перечислители должны быть полными (имя :: идентификатор). По этой причине нельзя определить анонимное управляемое перечисление.
Перечислители стандартного перечисления строго вводятся во внешнюю область. То есть, если есть другой символ с таким же именем, как у перечислителя во внешней области видимости, компилятор выдаст ошибку.
В Visual Studio 2002 и Visual Studio 2003 перечислители были нестрого вводимыми (видимыми во внешней области, если не было другого идентификатора с таким же именем).
Если стандартное перечисление C++ определено (без class или struct ), компиляция с /clr приведет к компиляции перечисления как управляемого перечисления. Перечисление по-прежнему имеет семантику неуправляемого перечисления. Обратите внимание, что компилятор вводит атрибут Microsoft::VisualC::NativeEnumAttribute для определения намерения программиста сделать перечисление собственным. Другие компиляторы просто увидят стандартное перечисление как управляемое перечисление.
Именованное стандартное перечисление, скомпилированное с параметром /clr , будет видимо в сборке как управляемое перечисление и может использоваться любым другим управляемым компилятором. Однако безымянное стандартное перечисление не будет видимо из сборки.
В Visual Studio 2002 и Visual Studio 2003 стандартное перечисление используется в качестве типа в параметре функции.
// mcppv2_enum.cpp // compile with: /clr enum E < a, b >; void f(E) int main()
Этот код выдал бы в MSIL для сигнатуры функции следующее:
Однако в текущих версиях компилятора стандартное перечисление выдается как управляемое перечисление с [NativeEnumAttribute], а в MSIL для сигнатуры функции выдается следующее:
Дополнительные сведения о неуправляемых перечислителях см. в разделе Объявление перечислений C++.
Дополнительные сведения о перечислителях CLR см. в следующем разделе:
Требования
Примеры
// mcppv2_enum_2.cpp // compile with: /clr // managed enum public enum class m < a, b >; // standard enum public enum n < c, d >; // unnamed, standard enum public enum < e, f >o; int main() < // consume managed enum m mym = m::b; System::Console::WriteLine("no automatic conversion to int: ", mym); System::Console::WriteLine("convert to int: ", (int)mym); // consume standard enum n myn = d; System::Console::WriteLine(myn); // consume standard, unnamed enum o = f; System::Console::WriteLine(o); >
no automatic conversion to int: b convert to int: 1 1 1
Перечисления (C++)
Перечисление — это определяемый пользователем тип, состоящий из набора именованных целочисленных констант, известных как перечислители.
В этой статье рассматриваются тип языка enum C++ стандарта ISO и тип с областью действия (или строго типизированный), enum class который появился в C++11. Сведения о типах public enum class или private enum class в C++/CLI и C++/CX см. в разделе enum class (C++/CLI и C++/CX).
Синтаксис
enum-specifier :
enum-head enumerator-list opt >
enum-head enumerator-list , >
opaque-enum-declaration :
enum-key attribute-specifier-seq Выбрать enum-head-name enum-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] ; // scoped enum: // enum [class|struct] [identifier] [: type] ; // 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 и т. д., но можно задать значение перечислителя явным образом, как показано ниже:
Перечислителю Diamonds присваивается значение 1 . Последующие перечислители, если им не присвоено явное значение, получают значение предыдущего перечислителя плюс один. В предыдущем примере Hearts имел бы значение 2, Clubs — значение 3 и т.д.
Каждый перечислитель обрабатывается как константа и должен иметь уникальное имя в область, где enum определен (для перечислений без ограничений) или внутри enum самого (для перечислений с заданной областью). Значения, присвоенные именам, не обязательно должны быть уникальными. Например, рассмотрим следующее объявление перечисления Suit без области :
Значения Diamonds , Hearts , Clubs и 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 a 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(account_num); // OK, but probably a bug. account_num = Suit::Hearts; // error C2440: '=' : cannot convert from 'Suit' to 'int' account_num = static_cast(Suit::Hearts); // OK > >
Обратите внимание, что в строке hand = account_num; по-прежнему содержится ошибка, которая происходит при использовании неограниченных перечислений, как показано выше. Это разрешено с явным приведением. Однако при использовании ограниченных перечислений попытка преобразования в следующем операторе — account_num = Suit::Hearts; — больше не будет разрешена без явного приведения.
Перечисления без перечислителей
Visual Studio 2017 версии 15.3 и более поздних версий (доступно в /std:c++17 и более поздних версиях). Определив перечисление (обычное или ограниченное) с явным базовым типом без перечислителей, вы можете ввести новый целочисленный тип, не имеющий неявного преобразования в любой другой тип. Используя этот тип вместо встроенного базового типа, можно исключить вероятность незначительных ошибок, вызванных непреднамеренно неявными преобразованиями.
enum class byte : unsigned char < >;
Новый тип является точной копией базового типа и, следовательно, имеет то же соглашение о вызовах, что означает, что его можно использовать в ABI без снижения производительности. Приведение не требуется, если переменные типа инициализируются с помощью инициализации прямого списка. В следующем примере показано, как инициализировать перечисления без перечислителей в различных контекстах:
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; >