类型安全的 C++ 枚举,带 ToString() 和 FromString()






4.73/5 (9投票s)
一个使用宏和模板实现的枚举,提供类型安全和类型信息
引言
C++ enum
缺乏编码人员经常需要的一些特性。例如,最后一个成员的值,以便迭代枚举的所有可能值。通常通过在 enum
中添加一个“last
”成员来解决这个问题。
enum MyEnum
{
MyEnum_member1,
MyEnum_member2,
MyEnum_Last
};
另一个导致头痛的问题是 enum
值与其 string
表示形式之间的转换。大多数人,尤其是初学者,最终会使用类似以下的代码来进行转换。
static const char* ENUM_STRINGS[MyEnum_Last] =
{
"MyEnum_member1",
"MyEnum_member2",
};
本文附带的代码提供了解决这些问题的方案。它已经在 VS2008 和 CygWin g++ 4.5.0 上进行了测试。
Using the Code
使用该代码很简单;只需将 SmartEnum.h 文件包含在您的项目中(可能在您的 stdafx.h 中),然后使用 SmartEnum.h 中提供的宏声明您的 enum
,如下所示:
BEGIN_SMART_ENUM(MyEnum)
ENUM_MEMBER(member1)
ENUM_MEMBER(member2)
END_SMART_ENUM(MyEnum)
您可以将此 enum
声明放置在任何位置,包括类声明和命名空间中,就像使用 C++ enum
一样。使用上述 enum
声明,以下代码片段演示了此 enum
如何解决在使用 C++ enum
时存在的问题。
使用您的 enum
成员
MyEnum e = MyEnum::member1;
迭代 enum
的成员
for (MyEnum i=MyEnum::FIRST; i<MyEnum::LAST; ++i)
printf("%d. MyEnum::%s\n", (int)i, i.ToString());
现在您还在 MyEnum
“命名空间”中拥有一些预定义的常量和方法,它们是:
MyEnum::FIRST
MyEnum::LAST == MyEnum::COUNT == MyEnum::INVALID
您还拥有一些有用的方法
static const char* MyEnum::ToString(const MyEnum& e);
const char* MyEnum::ToString() const;
static MyEnum MyEnum::FromString(const char* s);
static bool MyEnum::IsValid(const MyEnum& e);
bool MyEnum::IsValid() const;
// pre- and postfix -- and ++ operators required to iterate
可以根据您的项目需要添加其他有用的方法(例如:Serialize
)。
一个很酷的事情是,此 enum
会自动初始化为 MyEnum::INVALID
,从而更容易避免忘记初始化 enum
的常见错误。
当程序有很多具有相似成员名称的 enum
时,程序员很容易将不同类型的两个 enum
值进行比较。这会导致语法上有效但有缺陷的 C++ 代码,实际上可以编译,可能带有警告消息。C++ enum
也可以与 C++ 整数进行比较。本文提交的智能 enum
通常只能与相同类型进行比较;如果要进行其他操作,则必须将其转换为原始整型。
缺点
该解决方案有一些限制;让我们来看看它们
enum
的值存储在原始 C++ 类型(char
)中,这使得调试更加困难。为了克服这个问题,我添加了一个 (const char*
),它始终指向编译为调试模式时的成员名称,从而使enum
在调试/发布版本中大小不同。- 底层的模板元编程将
enum
成员的数量限制为32
。 - 这些宏生成的代码比普通的 C++
enum
编译速度慢得多。 - 目前,
FromString()
的时间复杂度为 O(n);可以将其优化为 O(log(n))。这样做会带来线程安全问题,因此目前我选择了这种更简单的解决方案。 - 成员不能像常规 C++
enum
一样具有自定义值。
历史
- 2010年11月13日:初始发布