众所周知,C++中的内置枚举不是类型安全的.我想知道实现类型安全枚举的哪些类在那里使用...我自己使用以下"自行车",但它有点冗长和有限:
typesafeenum.h:
struct TypesafeEnum { // Construction: public: TypesafeEnum(): id (next_id++), name("") {} TypesafeEnum(const std::string& n): id(next_id++), name(n) {} // Operations: public: bool operator == (const TypesafeEnum& right) const; bool operator != (const TypesafeEnum& right) const; bool operator < (const TypesafeEnum& right) const; std::string to_string() const { return name; } // Implementation: private: static int next_id; int id; std::string name; };
typesafeenum.cpp:
int TypesafeEnum::next_id = 1; bool TypesafeEnum::operator== (const TypesafeEnum& right) const { return id == right.id; } bool TypesafeEnum::operator!= (const TypesafeEnum& right) const { return !operator== (right); } bool TypesafeEnum::operator< (const TypesafeEnum& right) const { return id < right.id; }
用法:
class Dialog { ... struct Result: public TypesafeEnum { static const Result CANCEL("Cancel"); static const Result OK("Ok"); }; Result doModal(); ... }; const Dialog::Result Dialog::Result::OK; const Dialog::Result Dialog::Result::CANCEL;
另外: 我认为我应该更加具体地了解这些要求.我会试着总结一下:
优先级1:将枚举变量设置为无效值应该是不可能的(编译时错误),没有例外.
优先级2:使用单个显式函数/方法调用,可以将枚举值转换为int或从int转换.
优先级3:尽可能紧凑,优雅,方便的声明和使用
优先级4:将字符串值转换为字符串和从字符串转换.
优先级5 :(很高兴)迭代枚举值的可能性.
我目前正在玩Boost Vault(文件名enum_rev4.6.zip
)中的Boost.Enum提案.虽然它从未正式提交过包含在Boost中,但它可以原样使用.(缺少文档,但是通过明确的源代码和良好的测试来弥补.)
Boost.Enum允许你声明这样的枚举:
BOOST_ENUM_VALUES(Level, const char*, (Abort)("unrecoverable problem") (Error)("recoverable problem") (Alert)("unexpected behavior") (Info) ("expected behavior") (Trace)("normal flow of execution") (Debug)("detailed object state listings") )
并让它自动扩展到:
class Level : public boost::detail::enum_base{ public: enum domain { Abort, Error, Alert, Info, Trace, Debug, }; BOOST_STATIC_CONSTANT(index_type, size = 6); Level() {} Level(domain index) : boost::detail::enum_base (index) {} typedef boost::optional optional; static optional get_by_name(const char* str) { if(strcmp(str, "Abort") == 0) return optional(Abort); if(strcmp(str, "Error") == 0) return optional(Error); if(strcmp(str, "Alert") == 0) return optional(Alert); if(strcmp(str, "Info") == 0) return optional(Info); if(strcmp(str, "Trace") == 0) return optional(Trace); if(strcmp(str, "Debug") == 0) return optional(Debug); return optional(); } private: friend class boost::detail::enum_base ; static const char* names(domain index) { switch(index) { case Abort: return "Abort"; case Error: return "Error"; case Alert: return "Alert"; case Info: return "Info"; case Trace: return "Trace"; case Debug: return "Debug"; default: return NULL; } } typedef boost::optional optional_value; static optional_value values(domain index) { switch(index) { case Abort: return optional_value("unrecoverable problem"); case Error: return optional_value("recoverable problem"); case Alert: return optional_value("unexpected behavior"); case Info: return optional_value("expected behavior"); case Trace: return optional_value("normal flow of execution"); case Debug: return optional_value("detailed object state listings"); default: return optional_value(); } } };
它满足您列出的所有五个优先级.
一个很好的折衷方法是:
struct Flintstones { enum E { Fred, Barney, Wilma }; }; Flintstones::E fred = Flintstones::Fred; Flintstones::E barney = Flintstones::Barney;
它与您的版本在同一意义上不是类型安全的,但是它的用法比标准枚举更好,并且您仍然可以在需要时利用整数转换.
我使用C++ 0x typesafe枚举.我使用一些帮助模板/宏来提供来自/来自字符串的功能.
enum class Result { Ok, Cancel};
我不.太多的开销太少了.此外,能够将枚举分类到不同的数据类型以进行序列化是一个非常方便的工具.我从来没有见过一个实例,其中"类型安全"枚举值得开销和复杂性,其中C++已经提供了足够好的实现.