これが最も人気のある例の1つです。クラシックと言えます。データは、たとえばjsonにシリアル化されます。構造には、(数値ではなく)テキスト形式で保存するenum-fieldがあります。すべて。やめる。C ++でこの基本的な問題を解決する簡単な方法はありません。(c)
...しかし、私は本当にしたいです。
過去1年間、ほとんどすべてのプロジェクトで、開発者がこの問題について独自のビジョンを提案した方法を見てきました。そして、どこにでもコードの重複があり、どこにでもある種のクラッチと「微妙さ」がありました。本当にそこにあるのは、私自身が時々このトピックに戻らなければならないことです。足りる。私は、少なくとも私自身のために、この問題を完全に終わらせることにしました。
コードは完璧にはほど遠いですが(匿名で修正されることを願っています)、それはその役割を果たします。多分誰かが重宝するでしょう:
実装
// 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とそれに相当する文字列の双射性セットを確保し、要素の数でユニバーサルの実装を作成することでした(さようなら、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にアップロードしました。
批評家は親切にレビューするように招待されています。