enum и enum class
enum — это простой способ объявить именованные константы времени компиляции.
Понятие перечисления
Заголовок раздела «Понятие перечисления»enum расшифровывается как enumeration — «перечисление», то есть исчерпывающий список возможных вариантов.
Допустим, вам нужно представить цвета светофора — как вы это сделаете?
Проще всего объявить по константе на каждый возможный цвет:
одну для красного, одну для желтого и одну для зеленого.
static inline const int RED = 0;static inline const int YELLOW = 1;static inline const int GREEN = 2;static здесь дает константам внутреннюю линковку: каждая единица трансляции
получает собственную копию, и линковщику нечего сопоставлять между файлами.
inline (для переменных — начиная с C++17) разрешает одинаковые определения
в нескольких единицах трансляции. Любой файл, которому нужны эти константы,
может просто подключить файл, где они объявлены, не заботясь о дублировании определений.
А использовать их можно, например, так.
По сути, именно это и делает enum.
Он просто позволяет объявлять такие константы с меньшими усилиями.
enum TrafficLightColors{ RED = 0, YELLOW = 1, GREEN = 2,};Более того, указывать значения становится необязательным. Если значения опустить, компилятор проставит их автоматически, увеличивая на единицу. Так что можно написать и так:
enum TrafficLightColors{ RED, YELLOW, GREEN,};Фактически это эквивалентно следующему:
enum TrafficLightColors{ RED = 0, YELLOW = RED + 1, GREEN = YELLOW + 1,};А если написать:
enum TrafficLightColors{ RED, YELLOW = 55, GREEN,};то получится эквивалент:
enum TrafficLightColors{ RED = 0, YELLOW = 55, GREEN = YELLOW + 1, // 56};enum class
Заголовок раздела «enum class»Было бы неплохо иметь возможность гарантировать, что целое число, передаваемое в некоторую функцию,
— это одно из перечисленных значений.
Сделать это можно с помощью struct. См. пример.
По сути, именно этого и позволяет добиться enum class, только с куда более простым синтаксисом.
См. пример.
Единственное важное отличие состоит в том, что в нашей реализации на
structконстанты необязательно объявлять внутри пространства имен, а вот вenum classони всегда объявлены именно там. Это означает, что все константы можно втянуть в текущую область видимости черезusing. Сenum classдо C++20 так поступить было нельзя, но начиная с C++20 естьusing enum TrafficLightColors;, которое импортирует перечислители в текущую область видимости.
Базовый тип
Заголовок раздела «Базовый тип»Перечисления не ограничены типом int — для представления значений подойдет любой другой целочисленный тип.
Например, можно взять байт, если максимальное значение меньше 256.
Для этого базовый тип указывается после имени перечисления.
#include <stdint.h>
enum TrafficLightColor : uint8_t // базовый тип, беззнаковое 8-битное целое{ RED = 0, YELLOW = 1, GREEN = 2,};Кстати, в переменную типа перечисления на самом деле можно записать недопустимое значение,
то есть значение, которое не совпадает ни с одной из констант.
В коде такого обычно не ожидают, поэтому, встретив где-то подобное значение,
разумнее всего вызвать assert(false), чтобы программа упала.
enum class TrafficLightColor // : int // неявно int{ RED = 0, YELLOW = 1, GREEN = 2,};
int main(){ // Создание недопустимого цвета разрешено. TrafficLightColor color = static_cast<TrafficLightColor>(5); return 0;}