Перечисления (enum) представляют еще один способ определения своих типов. Их отличительной особенностью является то, что они содержат набор числовых констант. Перечисление имеет следующую форму:
enum class имя_перечисления { константа_1, константа_2, ... константа_N};
После ключевых enum class идет название перечисления, и затем в фигруных скобках перечисляются через запятую константы перечисления.
Определим простейшее перечисление:
enum class Day {Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday}
В данном случае перечисление называется Day и представляет дни недели. В фигурных скобках заключены все дни недели. Фактически они представляют числовые константы.
Каждой константе сопоставляется некоторое числовое значение. По умолчанию первая константа получает в качестве значения 0, а остальные увеличиваются на единицу. Так, в примере
выше Monday
будет иметь значение 0, Tuesday
- 1 и так далее. Таким образом, последняя константа - Sunday
будет равна 6.
После создания перечисления мы можем определить его переменную и присвоить ей одну из констант:
Day today {Day::Thursday}; // или так //Day today = Day::Thursday;
В данном случае определяется переменная today
, которая равна Day::Thursday
, то есть четвертой константе перечисления Day.
Чтобы вывести значение переменной на консоль, можно использовать преобразование к типу целочисленному типу:
#include <iostream> enum class Day {Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday}; int main() { Day today {Day::Thursday}; std::cout << "Today: " << static_cast<int>(today) << std::endl; }
То есть в данном случае на консоль будет выведено Today: 3
, так как константа Thursday
имеет значение 3.
Мы также можем управлять установкой значений в перечислении. Так, мы можем задать начальное значение для одной контанты, тогда у последуюших констант значение увеличивается на единицу:
enum class Day {Monday = 1, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday};
В данном случае Tuesday
будет равно 2, а Sunday
- 7.
Можно назначить каждой константе индивидуальное значение или сочетать этот подход с автоустановкой:
enum class Day {Monday = 2, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday=1};
В данном случае Saturday
будет равно 7, а Sunday
- 1.
Можно даже назначать двум константам одно и то же значение:
enum class Day {Monday = 1, Mon = 1, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday };
Здесь константы Monday
и Mon
имеют одно и то же значение.
Можно присвоить константам значение уже имеющихся констант:
enum class Day {Monday = 1, Mon = Monday, Tuesday = Monday + 1, Wednesday, Thursday, Friday, Saturday, Sunday };
Стоит учитывать, что константы перечисления должны представлять целочисленные константы. Однако мы можем выбрать другой целочисленный тип, например, char
:
enum class Operation: char {Add = '+', Subtract='-', Multiply='*'};
Если мы захотим вывести значения этих констант на консоль в виде символов, то необходимо преобразовать их к типу char
:
#include <iostream> enum class Operation: char {Add = '+', Subtract='-', Multiply='*'}; int main() { std::cout << "add: " << static_cast<char>(Operation::Add) << std::endl; std::cout << "subtracte: " << static_cast<char>(Operation::Subtract) << std::endl; std::cout << "multiply: " << static_cast<char>(Operation::Multiply) << std::endl; }
Перечисления удобны, когда необходимо хранить ограниченный набор состояний и в зависимости от текущего состояния выполнять некоторые действия. Например:
#include <iostream> enum class Operation {Add, Subtract, Multiply}; void calculate(int n1, int n2, Operation op) { switch (op) { case Operation::Add: std::cout << n1 + n2 << std::endl; break; case Operation::Subtract: std::cout << n1 - n2 << std::endl; break; case Operation::Multiply: std::cout << n1 * n2 << std::endl; break; } } int main() { calculate(10, 6, Operation::Add); // 16 calculate(10, 6, Operation::Subtract); // 4 calculate(10, 6, Operation::Multiply); // 60 }
В данном случае все арифметические операции хранятся в перечислении Operation. В функции calculate зависимости от значения третьего параметра - применяемой операции выполняются определенные действия с двумя первыми параметрами.
При обращении к контантам перечисления по умолчанию необходимо указывать название перечисления, например, Day::Monday
. Но начиная со стандарта C++20 мы можем подключить
константы перечисления в текущий контекст с помощью оператора using.
using enum Day;
И в дальнейшем использовать только имя констант:
#include <iostream> enum class Day {Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday}; using enum Day; // подключаем константы перечисления в текущую область видимости int main() { Day today {Thursday}; // используем только имя константы // или так //Day today = Thursday; std::cout << static_cast<int>(today) << std::endl; // 3 // выводим значение констаты Sunday std::cout << static_cast<int>(Sunday) << std::endl; // 6 }
Также мы можем подключить только одну константу:
using Day::Monday; // подключаем только Monday ........................ Day today {Monday};
В данном случае подключаем только константу Day::Monday
. Для обращения к дргуим константам по прежднему необходимо использовать имя перечисления.
Поскольку такая возможность добавлена лишь начиная со стандарта С++20, то при компиляции с g++ или clang++ добавляется соответствующий флаг - -std=c++20
Стоит отметить, что раньше в С++ использовалась другая форма перечислений, которые пришли из языка С и определяются без ключевого слова class
:
#include <iostream> enum Day {Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday}; int main() { Day today = Tuesday; std::cout << today << std::endl; // 1 }
Такие перечисления еще называют unscoped
(то есть не ограниченные ни какой областью видимостью). Естественно такие перечисления можно встретить в старых
программах. Однако в виду того, что они потенциально могут привести к большему количеству ошибок, то в настоящее время такая форма все меньше и меньше используется.