Я пытался имитировать перечисления Java.Вот что я придумал:
template<typename Enumeration_Type>
class Enumeration {
public:
static auto get(int value) -> const Enumeration_Type& {
const auto result = getMap().find(value);
return *dynamic_cast<const Enumeration_Type*>(result->second);
};
const int value;
Enumeration(const Enumeration& other) = delete;
Enumeration(Enumeration&& other) noexcept = delete;
auto operator=(const Enumeration& other) -> Enumeration& = delete;
auto operator=(Enumeration&& other) noexcept -> Enumeration& = delete;
virtual operator int() const noexcept { return value; }
protected:
explicit constexpr Enumeration(const int value)
: value{value} { getMap().emplace(value, this); }
~Enumeration() = default;
private:
static auto getMap() noexcept -> std::unordered_map<int, const Enumeration<Enumeration_Type>*>& {
static std::unordered_map<int, const Enumeration<Enumeration_Type>*> map;
return map;
}
};
}
Это базовый класс для перечислений, он регистрирует указатели на экземпляры производных типов в конструкторе - таким образом он позволяет статическому методу get()
получать доступ к перечислениям с помощьюназначенные значения.А вот производный класс:
class DataType final: public Enumeration<DataType> {
public:
static const DataType UNSIGNED_INT;
// Other types...
const std::string_view name;
using Enumeration<DataType>::get;
private:
constexpr DataType(const int value, const std::string_view name) noexcept
: Enumeration<DataType>{value},
name{name} {}
};
Вслед за исходным файлом:
const DataType DataType::UNSIGNED_INT{0x1405, "UNSIGNED INT"};
// Other types...
Кажется, это работает, но я боюсь, что не может быть никакой гарантии для статических членов впроизводный класс для инициализации и регистрации через конструктор перед первым вызовом get()
в базовом классе.Например: может ли произойти следующее: карта в базовом классе пуста при вызове get()
?