当然,最简单的解决方案是为每个枚举编写一个函数来执行到字符串的转换:
enum OS_type { Linux, Apple, Windows };
inline const char* ToString(OS_type v)
{
switch (v)
{
case Linux: return "Linux";
case Apple: return "Apple";
case Windows: return "Windows";
default: return "[Unknown OS_type]";
}
}
然而,这是一场维护灾难。借助可与 C 和 C++ 代码一起使用的 Boost.Preprocessor 库,您可以轻松利用预处理器并让它为您生成此函数。生成宏如下:
#include <boost/preprocessor.hpp>
#define X_DEFINE_ENUM_WITH_STRING_CONVERSIONS_TOSTRING_CASE(r, data, elem) \
case elem : return BOOST_PP_STRINGIZE(elem);
#define DEFINE_ENUM_WITH_STRING_CONVERSIONS(name, enumerators) \
enum name { \
BOOST_PP_SEQ_ENUM(enumerators) \
}; \
\
inline const char* ToString(name v) \
{ \
switch (v) \
{ \
BOOST_PP_SEQ_FOR_EACH( \
X_DEFINE_ENUM_WITH_STRING_CONVERSIONS_TOSTRING_CASE, \
name, \
enumerators \
) \
default: return "[Unknown " BOOST_PP_STRINGIZE(name) "]"; \
} \
}
第一个宏(以X_
) 由第二个内部使用。第二个宏首先生成枚举,然后生成ToString
函数接受该类型的对象并将枚举器名称作为字符串返回(由于显而易见的原因,此实现要求枚举器映射到唯一值)。
在 C++ 中你可以实现ToString
功能作为operator<<
相反,重载,但我认为需要显式的“更干净”ToString
" 将值转换为字符串形式。
作为一个使用示例,您的OS_type
枚举定义如下:
DEFINE_ENUM_WITH_STRING_CONVERSIONS(OS_type, (Linux)(Apple)(Windows))
虽然宏乍一看似乎需要大量工作,并且定义OS_type
看起来很陌生,记住你必须编写一次宏,然后你可以将它用于每个枚举。您可以向其添加附加功能(例如,字符串形式到枚举的转换),而不会太麻烦,并且它完全解决了维护问题,因为您只需在调用宏时提供一次名称。
然后可以像正常定义一样使用枚举:
#include <iostream>
int main()
{
OS_type t = Windows;
std::cout << ToString(t) << " " << ToString(Apple) << std::endl;
}
这篇文章中的代码片段,从#include <boost/preprocessor.hpp>
行,可以按发布的方式进行编译以演示解决方案。
这个特定的解决方案适用于 C++,因为它使用 C++ 特定的语法(例如,没有typedef enum
) 和函数重载,但是用 C 语言也可以很简单地实现这一点。