65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.73/5 (9投票s)

2010年11月14日

CPOL

2分钟阅读

viewsIcon

45156

downloadIcon

465

一个使用宏和模板实现的枚举,提供类型安全和类型信息

引言

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日:初始发布
© . All rights reserved.