【发布时间】:2018-06-03 17:55:50
【问题描述】:
我试图模仿 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() 时基类中的地图为空?
【问题讨论】:
-
变量
UNSIGNED_INT是在动态初始化阶段创建的。这是在调用main之前。因此,如果您不在另一个 ctor 中访问 get(),那么您是安全的。 -
不要尝试用 C++ 编写 Java,反之亦然。它们是非常不同的语言。您可能持有的关于一种语言的假设将不适用于另一种语言。您需要从头开始学习新语言,并忘记您对旧语言的了解。语法看似相似,但不要让它愚弄你; 语义即使对于相似的语法也是不同的。
-
@JesperJuhl 像这样的枚举类对于存储与多个值相关联并且可由其中一个值识别的常量不是很有用吗? c++ 枚举允许每个枚举只存储一个值 - 更不用说您不能按值要求其中之一。
-
@AustinReuter 你总是使用尾随返回类型有什么原因吗?看起来有点不方便。
-
@kiloalphaindia 一旦你习惯了它就不会不方便。我这样做是为了与情况保持一致,当我必须使用或当我想跳过内联 getter 中的返回类型时。
标签: c++ enums static initialization