Это статья о языке программирования C++.
Элементы обычного перечисление (enum
) запросто могут применяться в качестве ключа в unordered_map
. Следующий пример показывает, как сопоставить элемент перечисления с текстовым значением.
#include <string>
#include <iostream>
#include <unordered_map>
enum Color { Red, Blue, Green, };
int main()
{
std::unordered_map<int, std::string> colors {
{Red, "Red"},
{Blue, "Blue"},
{Green, "Green"},
};
std::cout << colors.at(Red) << std::endl;
}
Этот пример выведет в консоль слово «Red». Заметьте, что тип ключа — int
.
Такое перечисление не типобезопасно и устарело. Язык C++11 предоставляет типобезопасные перечисления (enum class
). У такого перечисления для доступа к элементам надо указывать имя перечисления.
Ниже приведен пример типобезопасного перечисления.
enum class Month
{
January,
February,
March,
April,
May,
June,
July,
August,
September,
October,
November,
December,
};
Чтобы получить доступ к элементу January
, нужно написать Month::January
.
Элементы такого перечисления можно использовать в аналогичном unordered_map
, но только с явным привидением типа с помощью static_cast
. Пример:
int main()
{
std::unordered_map<int, std::string> colors{
{static_cast<int>(Month::January), "January"},
{static_cast<int>(Month::February), "February"},
};
std::cout << colors.at(static_cast<int>(Month::January)) << std::endl;
}
Использование static_cast
делает код громоздким.
Код ниже показывает, как создать unordered_map
, у которого в качестве ключа элементы типобезопасного перечисления, и где не требуется приведение типа.
#include <string>
#include <iostream>
#include <unordered_map>
struct EnumClassHash
{
template <typename T>
std::size_t operator()(T t) const
{
return static_cast<std::size_t>(t);
}
};
enum class Month
{
January,
February,
March,
April,
May,
June,
July,
August,
September,
October,
November,
December,
};
int main()
{
std::unordered_map<Month, std::string, EnumClassHash> months{
{Month::January, "January"},
{Month::February, "February"},
{Month::March, "March"},
{Month::April, "April"},
{Month::May, "May"},
{Month::June, "June"},
{Month::July, "July"},
{Month::August, "August"},
{Month::September, "September"},
{Month::October, "October"},
{Month::November, "November"},
{Month::December, "December"},
};
std::cout << months.at(Month::January) << std::endl;
}
Ключевую роль здесь играет класс EnumClassHash
. Он указывается в качестве шаблонного параметра при объявлении unordered_map
. Этот класс возвращает хеш от элемента перечисления, при чем делает это максимально эффективным способом. В качестве хеша выступает значение самого элемента перечисления.
Таким образом можно создавать сколько угодно unordered_map
c различными перечислениями, используя один единственный класс EnumClassHash
. Иначе пришлось бы в пространстве имен std
определять хеш-функцию для каждого перечисления.
Данный способ почерпнут в одном вопросе на StackOverflow.