Enum проти сильно набраного enum


84

Я новачок у програмуванні на C ++.

Сьогодні я натрапляю на нову тему: сильно набрана enum. Я трохи досліджував це, але дотепер я не можу з'ясувати, навіщо це нам потрібно і яка користь від того самого?

Наприклад, якщо ми маємо:

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

Навіщо нам писати:

enum class xyz{a, b, c};

Що ми тут намагаємось робити? Мій найголовніший сумнів - це як ним користуватися. Не могли б ви навести невеликий приклад, який змусить мене зрозуміти.

Відповіді:


114

Добре, перший приклад: перерахування старого стилю не мають власного обсягу:

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?

Нарешті, ви можете вказати базовий інтегральний тип перерахувань C ++ 11:

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

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


Чи потрібно нам оголошувати / визначати enum class Coloursта enum class Fruits. Тому що , коли я писав код в VS 2010. Він видає помилку "expects a defination or a tag name"при class.
Rasmi Ranjan Nayak

Також: Для "звичайного" переліку в C ++ 11, як у C ++ 98, базовий тип за замовчуванням не визначений
bruziuz

2
Також: Ви можете зробити переадресацію enum-s, якщо вказано базовий тип. Для звичайного переліку в C ++ 11, C ++ 98 це не дозволено. Компілятор Microsoft дозволяє вам робити переадресацію enum, але це лише розширення MS, воно не є стандартним (наприклад, gcc не дозволяє) Отже, така річ зараз є законною: enum ForwardDeclare: std :: uint8_t;
bruziuz

Чи можемо ми мати обчислення переліків, які також неявно перетворюються на цілісний тип?
SS Anne

17

На цій сторінці IBM є хороша стаття про переліки , вона дуже детальна і добре написана. Ось кілька важливих моментів у двох словах:

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

  • Ви отримуєте безпеку типу, забороняючи всі неявні перетворення перелічених областей в інші типи.
  • Ви отримуєте нову область дії, і перерахування більше не знаходиться в області, що охоплює, рятуючи себе від конфліктів імен.
  • Scoped enums дає вам можливість вказати основний тип перелічення, а для scoped enum за замовчуванням це int, якщо ви вирішите не вказати його.
  • Будь-яке перерахування з фіксованим базовим типом може бути оголошено вперед.

2
Третій та четвертий пункти не є специфічними для переліків з масштабом; Ви можете вказати базовий тип будь-якого переліку.
Mike Seymour

1
Хтось має посилання на менш пошкоджену версію PDF? Приклади коду в ньому не відображаються в жодному з моїх переглядачів PDF, що залишає багато для уяви.
Sara Sinback

11

Значення enum classдійсно типу enum class, а не underlying_typeяк для С-переліків.

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);

5

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

  1. звичайне enumsнеявне перетворення в int, викликаючи помилки, коли хтось не хоче, щоб перелік діяв як ціле число.
  2. звичайні enumsекспортують свої перечислювачі в навколишнє середовище, викликаючи зіткнення імен.
  3. Основний тип an 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 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класи використовуються для:

  1. Картування системи специфічні коди помилок: В <system_error>: enum class errc;
  2. Показники безпеки покажчика: В <memory>:enum class pointer_safety { relaxed, preferred, strict };
  3. Помилки потоку вводу-виводу: У <iosfwd>:enum class io_errc { stream = 1 };
  4. Обробка помилок асинхронного зв'язку: У <future>:enum class future_errc { broken_promise, future_already_retrieved, promise_already_satisfied };

Деякі з них мають оператори, такі як ==визначені.


3

Enum Scope

Перерахування експортують свої перечислювачі в навколишнє поле. Це має два недоліки. По-перше, це може призвести до зіткнень імен, якщо два перечислювачі в різних переліченнях, оголошених в одному і тому ж обсязі, мають одне і те ж ім'я; по-друге, неможливо використовувати перелічувач із повністю кваліфікованим іменем, включаючи ім'я переліку.

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

select = ESet::a; // error
select = a;       // is ambigious
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.