[C++] C++ enum <-> string? Легко
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Вот, скажем, один из самых популярных примеров. Можно сказать, классических. Сериализуются данные в, скажем, 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
===========
Похожие новости:
- [C++, Программирование] Антипаттерн “константа размера массива” (перевод)
- [Разработка веб-сайтов, Python, Программирование, C++] Разработка python module, чтобы продакшн радовал
- [Занимательные задачки, Программирование, C++, Алгоритмы] Обобщение классической задачи на множества с собеседований
- [Информационная безопасность, DevOps] DevSecOps: организация фаззинга исходного кода
- [Qt, Карьера в IT-индустрии, История IT, Биографии гиков] Как Qt сделал студента [человеком]
- [C++, Программирование] ИСО одобрила С++ 20, стандарт будет опубликован к концу года
- [C++, Визуализация данных, Программирование, Учебный процесс в IT] Красиво? Очень! Как мы написали приложение для визуализации аттракторов
- [C++, Qt] Кастомные QSettings::ReadFunc и QSettings::WriteFunc, или как я написал костыль для русификации файла настроек
- [Программирование, C++] std::atomic. Модель памяти C++ в примерах
- [Программирование, .NET] Enum и switch, и что с ними не так
Теги для поиска: #_c++, #_enum, #_serialization, #_c++
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 25-Ноя 17:17
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Вот, скажем, один из самых популярных примеров. Можно сказать, классических. Сериализуются данные в, скажем, 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)) // 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; } =========== Источник: habr.com =========== Похожие новости:
|
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 25-Ноя 17:17
Часовой пояс: UTC + 5