问题描述
常见的是,C ++中的内置枚举不是TypeAfe. 我想知道在那里使用了哪些实施类型的枚举的类... 我本人使用以下"自行车",但有些详细且有限:
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转换枚举值.
优先级3:尽可能紧凑,优雅,方便的声明和使用
优先级4:将枚举值转换为和从字符串转换.
优先级5 :(很高兴有)可能迭代枚举值的可能性.
推荐答案
我目前正在使用 boost Vault (文件名enum_rev4.6.zip).尽管从未正式提交过将其纳入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<Level, string> { public: enum domain { Abort, Error, Alert, Info, Trace, Debug, }; BOOST_STATIC_CONSTANT(index_type, size = 6); Level() {} Level(domain index) : boost::detail::enum_base<Level, string>(index) {} typedef boost::optional<Level> 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<Level, string>; 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<value_type> 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;
它不是您的版本的类型AFTE,但是使用情况比标准枚举更好,并且在需要时您仍然可以利用整数转换.
其他推荐答案
我使用 c ++ s typesafe enums c ++ spectsafe enums .我使用一些提供TO/来自字符串功能的辅助模板/宏.
enum class Result { Ok, Cancel};
问题描述
It is common knowledge that built-in enums in C++ are not typesafe. I was wondering which classes implementing typesafe enums are used out there... I myself use the following "bicycle", but it is somewhat verbose and limited:
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; }
Usage:
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;
Addition: I think I should have been more specific about the requirements. I'll try to summarize them:
Priority 1: Setting an enum variable to an invalid value should be impossible (a compile-time error) with no exceptions.
Priority 2: Converting an enum value to/from an int should be possible with a single explicit function/method call.
Priority 3: As compact, elegant and convenient declaration and usage as possible
Priority 4: Converting enum values to and from strings.
Priority 5: (Nice to have) Possibility to iterate over enum values.
推荐答案
I'm currently playing around with the Boost.Enum proposal from the Boost Vault (filename enum_rev4.6.zip). Although it was never officially submitted for inclusion into Boost, it's useable as-is. (Documentation is lacking but is made up for by clear source code and good tests.)
Boost.Enum lets you declare an enum like this:
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") )
And have it automatically expand to this:
class Level : public boost::detail::enum_base<Level, string> { public: enum domain { Abort, Error, Alert, Info, Trace, Debug, }; BOOST_STATIC_CONSTANT(index_type, size = 6); Level() {} Level(domain index) : boost::detail::enum_base<Level, string>(index) {} typedef boost::optional<Level> 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<Level, string>; 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<value_type> 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(); } } };
It satisfies all five of the priorities which you list.
其他推荐答案
A nice compromise method is this:
struct Flintstones { enum E { Fred, Barney, Wilma }; }; Flintstones::E fred = Flintstones::Fred; Flintstones::E barney = Flintstones::Barney;
It's not typesafe in the same sense that your version is, but the usage is nicer than standard enums, and you can still take advantage of integer conversion when you need it.
其他推荐答案
I use C++0x typesafe enums. I use some helper template/macros that provide the to/from string functionality.
enum class Result { Ok, Cancel};