Русский
Русский
English
Статистика
Реклама

C enum lt-gt string? Легко

Вот, скажем, один из самых популярных примеров. Можно сказать, классических. Сериализуются данные в, скажем, json. В структуре есть enum-поле, которое хочется сохранять в текстовом виде (а не числом). Всё. Стоп. Простого способа решить эту элементарную задачу на 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).

Главная идея была в том, чтобы гарантировать биективность множества enum и его строкового эквивалента, а также сделать реализацию универсальной по количеству элементов (до свидания, вырвиглазный хардкодный макрос _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.

Любезно приглашаю критиков на ревью.

Источник: habr.com
К списку статей
Опубликовано: 12.09.2020 20:07:24
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

C++

Enum

Serialization

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru