Cpp 中如何优雅进行 enum 到 string 的转换


概述

这里不介绍非侵入式的写法,具体想要了解的话可以观看这篇文章,这里仅介绍通过宏写法来进行转换的情况。

这里拿minilog的log-level定义来介绍,首先肯定是需要按照等级先进行定义:

#define MINILOG_FOREACH_LOG_LEVEL(f) \
  f(trace) f(debug) f(info) f(critical) f(warn) f(error) f(fatal)

后续如果要修改只用修改这一处就行了,优点是一劳永逸,不存在维护额外开销的问题,当然缺点也有,比如在写server的时候遇到过需要将传入的指令进行与操作整合的情况,这种类型的情况下就无法使用宏的方法,或者说需要额外处理。

在定义好各个level后就需要进行enum的声明了:

enum class log_level : std::uint8_t {
#define _FUNCTION(name) name,
  MINILOG_FOREACH_LOG_LEVEL(_FUNCTION)
#undef _FUNCTION
};

具体来说就是将log_level在enum中用宏函数进行了展开,避免无用代码的编写。接下来是文章的核心,怎么进行enum和string的相互转化。

inline std::string log_level_name(log_level level) {
  switch (level) {
#define _FUNCTION(name) \
  case log_level::name: \
    return #name;
    MINILOG_FOREACH_LOG_LEVEL(_FUNCTION)
#undef _FUNCTION
  }
  return "unknown";
}

inline log_level log_level_from_name(std::string_view lev) {
#define _FUNCTION(name) \
  if (lev == #name) return log_level::name;
  MINILOG_FOREACH_LOG_LEVEL(_FUNCTION)
#undef _FUNCTION
  return log_level::info;
}

非常方便,相当于自动维护对应的代码,事实上,clang 在定义TokenKind的时候,就是这么做的,具体的案例请参考。由于 clang 要适配多种语言前端,最后总计的TokenKind有几百个之多。如果不这样做,可想而知,进行Token的增加和修改会十分困难。


文章作者: JoyTsing
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 JoyTsing !
评论
  目录