Объявления перечислений C++

Перечисление — это пользовательский тип, состоящий из набора целочисленных констант, называемых перечислителями.

Примечание

В этом разделе рассматривается тип enum языка C++ стандарта ISO, а также ограниченный (строго типизированный) тип enum class, который впервые введен в C++11.Сведения о типах public enum class и private enum class в C++/CLI и C++/CX см. в разделе класс enum.

// unscoped enum:
enum [identifier] [: type]

{enum-list}; 

// scoped enum:
enum [class|struct] 
[identifier] [: type] 
{enum-list};

Параметры

  • identifier
    Имя типа, присваиваемое перечислению.

  • type
    Базовый тип перечислителей; все перечислители имеют один базовый тип. Может быть любым целочисленным типом.

  • enum-list
    Разделенный запятыми список перечислителей в перечислении. Каждый перечислитель или имя переменной в области должны быть уникальными. Однако значения могут повторяться. В неограниченном перечислении областью видимости является окружающая область; в ограниченном перечислении областью видимости является сам список enum-list.

  • class
    Используя это ключевое слово в объявлении, вы указываете, что перечисление ограничено и необходимо предоставить identifier. Кроме того, ключевое слово struct используется вместо class, так как в этом контексте они семантически эквивалентны.

Заметки

Перечисление предоставляет контекст для описания диапазона значений, которые представлены в виде именованных констант и также называются перечислителями. В первоначальных типах перечислений C и C++ перечислители с неполным имеем являются видимыми внутри области видимости, в которой объявлено перечисление. В ограниченных перечислениях имя перечислителя должно уточняться именем типа перечисления. В следующем примере демонстрируется основное различие между двумя видами перечислений.

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 (для неограниченных перечислений), или в самом перечислении (для ограниченных перечислений). Значения, задаваемые имена, могут быть неуникальными. Например, для следующего объявления неограниченного перечисления Suit:

enum Suit { Diamonds = 5, Hearts, Clubs = 4, Spades };

значения 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<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; — больше не будет разрешена без явного приведения.

См. также

Ссылки

Объявления перечислений C

Ключевые слова в C++