C ++枚举<->字符串?简单

这是最受欢迎的示例之一。我们可以说经典。数据被序列化为json。该结构具有您要以文本形式(而不是数字)保存的枚举字段。所有。停止。没有简单的方法可以解决C ++中的这一基本任务。(C)

...但是我真的很想。

在过去的一年中,我已经看到开发人员在几乎每个项目中如何提出自己对这个问题的看法。到处都有重复的代码,到处都有拐杖和“微妙之处”。实际情况是什么,我本人必须不时回到这个话题。足够。我决定一劳永逸地解决这个问题,至少是对我自己。

该代码远非完美(我希望匿名者可以对其进行纠正),但是它确实可以做到。也许有人会派上用场:

实作
// enum_string.h
#pragma once

#define DECLARE_ENUM(T, values...)                                    \
  enum class T { values, MAX };                                       \
  char enum_##T##_base[sizeof(#values)] = #values;                    \
  const char* T##_tokens[static_cast<__underlying_type(T)>(T::MAX)];  \
  const char* const* T##_tmp_ptr = tokenize_enum_string(              \
      const_cast<char*>(enum_##T##_base), sizeof(#values), T##_tokens,\
      static_cast<__underlying_type(T)>(T::MAX));

#define enum_to_string(T, value) \
  (T##_tokens[static_cast<__underlying_type(T)>(value)])

static const char* const* tokenize_enum_string(char* base,
                                               int length,
                                               const char* tokens[],
                                               int size) {
  int count = 0;
  tokens[count++] = base;
  for (int i = 1; i < length; ++i) {
    if (base[i] == ',') {
      base[i] = '\0';

      if (count == size) {
        return tokens;
      }

      do {
        if (++i == length) {
          return tokens;
        }

      } while (' ' == base[i]);

      tokens[count++] = base + i;
    }
  }

  return tokens;
}

static bool string_equals(const char* a, const char* b) {
  int i = 0;
  for (; a[i] && b[i]; ++i) {
    if (a[i] != b[i]) {
      return false;
    }
  }

  return (a[i] == b[i]);
}

static int string_to_enum_int(const char* const tokens[], int max,
                              const char* value) {
  for (int i = 0; i < max; ++i) {
    if (string_equals(tokens[i], value)) {
      return i;
    }
  }

  return max;
}
#define string_to_enum(T, value)     \
  static_cast<T>(string_to_enum_int( \
      T##_tokens, static_cast<__underlying_type(T)>(T::MAX), value))

您可以轻松地用自己喜欢的库替换使用字符串,这里的大多数代码只是字符串解析(我真的很想在没有STL的情况下这样做)。

主要思想是确保枚举及其字符串等效的双射集,并在元素数量(再见,vyrviglazny hardkodny宏_NARG)中实现通用性好吧,这样使用尽可能可爱。

使用实例
// main.cpp
#include <iostream>

#include "enum_string.h"

DECLARE_ENUM(LogLevel,  // enum class LogLevel
             Alert,     // LogLevel::Alert
             Critical,  // LogLevel::Critical
             Error,     // LogLevel::Error
             Warning,   // LogLevel::Warning
             Notice,    // LogLevel::Notice
             Info,      // LogLevel::Info
             Debug      // LogLevel::Debug
             );

int main() {
  // serialize
  LogLevel a = LogLevel::Critical;
  std::cout << enum_to_string(LogLevel, a) << std::endl;

  // deserialize
  switch (string_to_enum(LogLevel, "Notice")) {
    case LogLevel::Alert: {
      std::cout << "ALERT" << std::endl;
    } break;
    case LogLevel::Critical: {
      std::cout << "CRITICAL" << std::endl;
    } break;
    case LogLevel::Error: {
      std::cout << "ERROR" << std::endl;
    } break;
    case LogLevel::Warning: {
      std::cout << "WARN" << std::endl;
    } break;
    case LogLevel::Notice: {
      std::cout << "NOTICE" << std::endl;
    } break;
    case LogLevel::Info: {
      std::cout << "INFO" << std::endl;
    } break;
    case LogLevel::Debug: {
      std::cout << "DEBUG" << std::endl;
    } break;
    case LogLevel::MAX: {
      std::cout << "Incorrect value" << std::endl;
    } break;
  }

  return 0;
}

对于我来说,它不需要其他解释。

另外,上传到github

敬请批评家进行评论。




All Articles