列挙型を文字列に変換したり、文字列を列挙型に変換したりするために、なぜそのようなツールが必要なのでしょうか?
プロジェクトが多すぎると、ログに列挙タグと整数タグを追加する必要がある場合があります。配列を出力するだけでは機能しません。問題がある場合は、ログを調べて 1 つずつクエリする必要があります。 . このとき、どうすればいいですか? if else をたくさん書いて、スイッチをたくさん書いて、文字を 1 つずつ一致させてください。小学生のコードとしか言いようがありません。汎用変換はできますか? 答えは間違いなく「はい」です。
Enum 文字列インターフェイスの設計
コード
#include <string>
#include <algorithm>
#include <vector>
template<typename E>
class EnumStrings {
public:
EnumStrings(std::initializer_list<std::pair<E, std::string> > list) {
m_eValue = m_stringValue = list;
std::sort(m_eValue.begin(), m_eValue.end(), CompareFirst);
std::sort(m_stringValue.begin(), m_stringValue.end(), CompareSecond);
}
inline static std::string ToString(E value) {
auto it = std::lower_bound(gSingleton.m_eValue.begin(),
gSingleton.m_eValue.end(), std::make_pair(value, std::string()), CompareFirst);
if(it == gSingleton.m_eValue.end() || it->first != value) {
assert(false);
return std::string();
}
return it->second;
}
inline static E FromString(const std::string& string, E fallback) {
auto it = std::lower_bound(gSingleton.m_stringValue.begin(),
gSingleton.m_stringValue.end(), std::make_pair((E) 0, string), CompareSecond);
if(it == gSingleton.m_stringValue.end() || it->second != string)
return fallback;
return it->first;
}
private:
static const EnumStrings gSingleton;
private:
std::vector<std::pair<E, std::string>> m_eValue;
std::vector<std::pair<E, std::string>> m_stringValue;
private:
inline static bool CompareFirst(const std::pair<E, std::string>& a, const std::pair<E, std::string>& b) {
return (a.first < b.first); }
inline static bool CompareSecond(const std::pair<E, std::string>& a, const std::pair<E, std::string>& b) {
return (a.second < b.second); }
};
template<typename E>
inline std::string EnumToString(E value) {
return EnumStrings<E>::ToString(value); }
template<typename E>
inline E StringToEnum(const std::string& string, E fallback) {
return EnumStrings<E>::FromString(string, fallback); }
#define ENUMSTRINGS(E) template<> const EnumStrings<E> EnumStrings<E>::gSingleton
- マインドマップのまとめ
- データは 2 つのベクトルに格納され、それぞれ列挙ソートと文字列ソート後の値が格納されます。
- テンプレート クラスなので、任意の型のテンプレート列を 1 つの列として宣言でき、列挙型のコピーはメモリ全体に 1 つだけ存在し、1 つの列挙型が 1 つのコピーに対応します。
- コンストラクターはパラメーターとして初期化されたリストを使用し、列挙値と文字列値を 1 つずつ渡して並べ替え、値をベクトルに保存します。
- 名前が示すように、toString は e を使用して対応する文字列を検索しますが、見つからない場合は当然空の文字列を返します。
- formString は、名前が示すように、文字列を使用して対応する列挙を検索します。ここにはフォールバックという興味深いパラメータがありますが、これは何を意味しますか?これは撤退、緊急時対応計画です。単刀直入に言うと、プラント B を意味します。意味自体は、フォールバック値が見つからない場合に返すことです。
- std:: lower_bound この関数は std アルゴリズムに含まれており、その意味は、ソートされたシーケンスに対して二分探索を使用し、ターゲット要素以上の最初のイテレータを返すことです。つまり、指定範囲クラスにおける検索対象は、検索結果>=対象値となります。
- 説明書。
#include <iostream>
#include "EunmStrings.h"
enum ETest
{
Login = 0,
LoginOut,
KikOut,
Disconnected,
};
ENUMSTRINGS(ETest) = {
{
Login, "login"},
{
LoginOut, "login out"},
{
KikOut, "kikout"},
{
Disconnected, "disconnected"},
};
int main(int argc, char** argv)
{
std::cout << "get string ETestf::Login = "
<< EnumToString(Login) << std::endl; // 模板自动推导得到响应的单例
std::cout << "get enum login = " << (int)StringToEnum("login", Login) << std::endl;
return 0;
}
出力
文字列を取得 ETestf::Login = ログイン
enum ログイン = 0 を取得
- オブジェクトのサイズを比較して文字列に変換することはできますか? 例えば、int型のフラグとstring型の中国語→英語変換ですが、結局のところ、英語1文と漢字1文は1対1に対応しています。
これはソースコード解析に関する単なる記事です
- このような独創的なアイデアは私のような一般人には思いつきません。また、文字、配列を文字列に変換し、値に対応する配列キーをマップすることも試しました。これは非常に危険です。配列が範囲外になる可能性があります。 map の場合、2 つ使用することもできます。1 つは E を保存し、もう 1 つは string を保存することで同じ効果を得ることができますが、私は愚かなのでそれを思いつきません。
- 最も重要なことは、これらのどれでもないということです。最も本質的な考え方は、名前空間には列挙が 1 つだけあり、それ以上ある場合は編集できないということです。列挙を使用してテンプレート クラス インスタンスを導出するシンボルの再定義。これに対応します。インターフェイス関数を呼び出すと、テンプレートからさまざまな種類の列挙型のシングルトンが直接取得され、それによって実際の値が取得されます。これは非常に賢明です。
template<typename E>
inline std::string EnumToString(E value) {
return EnumStrings<E>::ToString(value); }
template<typename E>
inline E StringToEnum(const std::string& string, E fallback) {
return EnumStrings<E>::FromString(string, fallback); }
#define ENUMSTRINGS(E) template<> const EnumStrings<E> EnumStrings<E>::gSingleton
- プロジェクトでは、1 回限りの並べ替えと迅速な削除のために Vector が使用されています。上司のアイデアは非常に先進的です。マップに変更しても問題ないように感じますが、少し遅くなるだけで、大幅に遅くなるわけではありません。このような大規模なプロジェクトでは、工学距離はほとんど無視できます。この設計には欠陥があります。列挙を繰り返した場合、結果は正しいでしょうか? マップは重複を直接削除し、ベクトルは保持されますが、その値より大きい最初の値のみが常に検出され、他の値を読み取ることはできません。ただし、これ自体はエラーですので、使用する場合は注意してください。コンパイル中に列挙型の重複を判断できるように設計できますか? テンプレートの機能にはまだあまり慣れていません。頭が痛いので今後考えます。
- 最後に、ソース コードを見てみましょう。これは ssr プロジェクト src/common/EnumStrings.h からのものです。githbub -ssrにアクセスして、常にアイデアに満ちた偉人たちのスタイルを目撃することができます。