Inilah salah satu contoh paling populer. Bisa dibilang klasik. Data tersebut diserialkan menjadi, katakanlah, json. Struktur memiliki kolom enum yang ingin Anda simpan dalam bentuk teks (bukan sebagai angka). Semua. Berhenti. Tidak ada cara mudah untuk memecahkan masalah dasar ini di C ++. (c)
... Tapi aku sangat ingin.
Selama setahun terakhir, saya telah melihat bagaimana di hampir setiap proyek, seorang pengembang mengajukan visinya sendiri tentang masalah ini. Dan di mana-mana ada duplikasi kode, di mana-mana ada semacam kruk, dan "seluk-beluk". Apa yang sebenarnya ada, saya sendiri harus kembali ke topik ini dari waktu ke waktu. Cukup. Saya memutuskan untuk menutup masalah ini untuk selamanya, setidaknya untuk diri saya sendiri.
Kode ini jauh dari sempurna (saya harap anonim akan memperbaikinya), tetapi berfungsi dengan baik. Mungkin seseorang akan berguna:
Penerapan
// 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))
Anda dapat dengan mudah mengganti bekerja dengan string dengan pustaka favorit Anda, sebagian besar kode di sini hanya parsing string (saya benar-benar ingin melakukannya tanpa STL).
Ide utamanya adalah untuk memastikan bijectivity set enum dan stringnya setara, dan membuat implementasi universal dalam jumlah elemen ( selamat tinggal, vyrviglazny hardkodny macro _NARG ). Nah, agar penggunaannya semanis mungkin.
contoh penggunaan
// 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;
}
Bagi saya, tidak perlu penjelasan tambahan.
Juga, diunggah ke github .
Para kritikus dengan hormat diundang untuk meninjau.