Подтвердить что ты не робот

Enum vs Сильно типизированное перечисление

Я начинаю программировать на С++.

Сегодня я сталкиваюсь с новой темой: строго набрал enum. Я исследовал это немного, но до сих пор я не могу выяснить, зачем нам это нужно и что это значит?

Например, если мы имеем:

enum xyz{a, b, c};
/*a = 0, b = 1, c = 2, (Typical C format)*/

Зачем нам писать:

enum class xyz{a, b, c};

Что мы пытаемся сделать здесь? Мое самое важное сомнение заключается в том, как его использовать. Не могли бы вы привести небольшой пример, который заставит меня понять.

4b9b3361

Ответ 1

ОК, первый пример: перечисления старого стиля не имеют своей собственной области:

enum Animals {Bear, Cat, Chicken};
enum Birds {Eagle, Duck, Chicken}; // error! Chicken has already been declared!

enum class Fruits { Apple, Pear, Orange };
enum class Colours { Blue, White, Orange }; // no problem!

Во-вторых, они неявно преобразуются в интегральные типы, что может привести к странному поведению:

bool b = Bear && Duck; // what?

Наконец, вы можете указать базовый интегральный тип С++ 11 перечислений:

enum class Foo : char { A, B, C};

Ранее базовый тип не указывался, что могло вызвать проблемы совместимости между платформами. Изменить. В комментариях указано, что вы также можете указать базовый интегральный тип перечня "старого стиля" в С++ 11.

Ответ 2

Там хорошая статья об enums на этой странице IBM, она очень подробно и хорошо написана. Вот несколько важных моментов:

Рекурсивные перечисления решают большинство ограничений, связанных с регулярными перечислениями: полная безопасность типов, четко определенный базовый тип, проблемы с областью и декларация.

  • Вы получаете безопасность типов, запрещая все неявные преобразования перечислимых областей в другие типы.
  • Вы получаете новую область, и перечисление больше не находится в закрывающей области, сохраняя себя от конфликтов имен.
  • Облачные области перечисления позволяют вам указать базовый тип перечисления, а для скопированных перечислений - по умолчанию - int, если вы решите не указывать его.
  • Любое перечисление с фиксированным базовым типом может быть объявлено вперед.

Ответ 3

Значения enum class действительно имеют тип enum class, а не underlying_type как для C-перечислений.

enum xyz { a, b, c};
enum class xyz_c { d, f, e };

void f(xyz x)
{
}

void f_c(xyz_c x)
{
}

// OK.
f(0);
// OK for C++03 and C++11.
f(a);
// OK with C++11.
f(xyz::a);
// ERROR.
f_c(0);
// OK.
f_c(xyz_c::d);

Ответ 4

Enum Scope

Перечисления экспортируют свои счетчики в окружающую область. Это имеет два недостатка. Во-первых, это может привести к конфликтам имен, если два перечисления в разных перечислениях, объявленных в одной области, имеют одно и то же имя; во-вторых, невозможно использовать перечислитель с полным именем, включая имя перечисления.

enum ESet {a0, a, a1, b1, c3};
enum EAlpha{a, b, c}

select = ESet::a; // error
select = a;       // is ambigious

Ответ 5

Классы перечисления ( "новые перечисления", "сильные перечисления" ) адресуют три проблемы с традиционными перечислениями С++:

  • обычный enums неявно преобразовать в int, вызывая ошибки, когда кто-то не хочет, чтобы перечисление выполнялось как целое число.
  • обычный enums экспортирует свои счетчики в окружающий объем, вызывая конфликты имен.
  • Нельзя указать базовый тип enum, вызывающий путаницу, проблемы с совместимостью и делает невозможным объявление вперед.

enum class ( "сильные перечисления" ) строго типизированы и ограничены:

enum Alert { green, yellow, orange, red }; // traditional enum

enum class Color { red, blue };   // scoped and strongly typed enum
                                  // no export of enumerator names into enclosing scope
                                  // no implicit conversion to int
enum class TrafficLight { red, yellow, green };

Alert a = 7;              // error (as ever in C++)
Color c = 7;              // error: no int->Color conversion

int a2 = red;             // ok: Alert->int conversion
int a3 = Alert::red;      // error in C++98; ok in C++11
int a4 = blue;            // error: blue not in scope
int a5 = Color::blue;     // error: not Color->int conversion

Color a6 = Color::blue;   // ok

Как показано, традиционные перечисления работают как обычно, но теперь вы можете по желанию квалифицироваться с именем перечисления.

Новые перечисления являются "enum class", потому что они объединяют аспекты традиционных перечислений (значения имен) с аспектами классов (охваченные члены и отсутствие преобразований).

Возможность указать базовый тип позволяет упростить взаимодействие и гарантировать размеры перечислений:

enum class Color : char { red, blue };  // compact representation

enum class TrafficLight { red, yellow, green };  // by default, the underlying type is int

enum E { E1 = 1, E2 = 2, Ebig = 0xFFFFFFF0U };   // how big is an E?
                                                 // (whatever the old rules say;
                                                 // i.e. "implementation defined")

enum EE : unsigned long { EE1 = 1, EE2 = 2, EEbig = 0xFFFFFFF0U };   // now we can be specific

Он также обеспечивает прямое объявление перечислений:

enum class Color_code : char;     // (forward) declaration
void foobar(Color_code* p);       // use of forward declaration
// ...
enum class Color_code : char { red, yellow, green, blue }; // definition

Основной тип должен быть одним из целочисленных типов с подписью или без знака; по умолчанию используется int.

В стандартной библиотеке классы enum используются для:

  • Сопоставление специфических кодов ошибок системы отображения: В <system_error>: enum class errc;
  • Индикаторы безопасности указателя: В <memory>: enum class pointer_safety { relaxed, preferred, strict };
  • Ошибки потока ввода/вывода: В <iosfwd>: enum class io_errc { stream = 1 };
  • Обработка ошибок асинхронной связи: В <future>: enum class future_errc { broken_promise, future_already_retrieved, promise_already_satisfied };

Некоторые из них имеют определенные операторы, такие как ==.