web-dev-qa-db-ja.com

C ++で列挙する文字列

テキストファイルの文字列を列挙値に関連付ける方法はありますか?

問題は次のとおりです。テキストファイルに文字列として格納されているいくつかの列挙値があり、ある条件を満たすときにその場で読み取ります...次に、読み取り値を列挙に割り当てます。

そうするための最も効果的な方法は何ですか?最も単純なアプローチである必要はありません。

17
Shree

何度も使用できるマップを設定できます。

template <typename T>
class EnumParser
{
    map <string, T> enumMap;
public:
    EnumParser(){};

    T ParseSomeEnum(const string &value)
    { 
        map <string, T>::const_iterator iValue = enumMap.find(value);
        if (iValue  == enumMap.end())
            throw runtime_error("");
        return iValue->second;
    }
};

enum SomeEnum
{
    Value1,
    Value2
};
EnumParser<SomeEnum>::EnumParser()
{
    enumMap["Value1"] = Value1;
    enumMap["Value2"] = Value2;
}

enum OtherEnum
{
    Value3, 
    Value4
};
EnumParser<OtherEnum>::EnumParser()
{
    enumMap["Value3"] = Value3;
    enumMap["Value4"] = Value4;
}

int main()
{
    EnumParser<SomeEnum> parser;
    cout << parser.ParseSomeEnum("Value2");
}
31
Eclipse
std::map< string, enumType> enumResolver;
9
tpdi

std::mapが最も簡単な解決策であるという多くの回答に同意します。

より高速なものが必要な場合は、ハッシュマップを使用できます。おそらく、コンパイラはhash_mapや今後の標準unordered_mapなどをすでに提供しているか、 boost から取得できます。すべての文字列が事前にわかっている場合は、 完全なハッシュ も使用できます。

3
Mark Ransom

Boost.Bimap を見てください。これは、2つの値のセット間の双方向の関連付けを提供します。基になるコンテナを選択することもできます。

2
Vadim Ferderer

承認された回答には完全なリストが含まれていません。受け入れられた回答から作成したEnumParser.hを追加します。お役に立てば幸いです。

#include <string>
#include <map>

using namespace std;

template <typename T> class EnumParser
{
    map<string, T> enumMap;
public:
    EnumParser(){};

    T ParseSomeEnum(const string &value)
    { 
        typename map <string, T>::const_iterator iValue = enumMap.find(value);
        if (iValue  == enumMap.end())
            throw runtime_error("");
        return iValue->second;
    }
};

使い方は簡単です:

enum FieldType
{
    Char,
    Integer,
    Long,
    Fixed,
    Price,
    Date,
    Time
};

EnumParser<FieldType>::EnumParser()
{
    enumMap["Char"] = Char;
    enumMap["Integer"] = Integer;
    enumMap["Long"] = Long;
    enumMap["Fixed"] = Fixed;
    enumMap["Price"] = Price;
    enumMap["Date"] = Date;
    enumMap["Time"] = Time;
}

使用する:

 EnumParser<FieldType> fieldTypeParser;
 FieldType val = fieldTypeParser.ParseSomeEnum(stringValue)
2
javapowered

これは、あなたの望むことですか?初期化は簡単で、インスタンス化は必要ありません。

使用法:

enum SomeEnum
{
    ENUM_ONE,
    ENUM_TWO,
    ENUM_THREE,
    ENUM_NULL
};

DEFINE_PAIRLIST(CEnumMap, SomeEnum)

INIT_PAIRLIST(CEnumMap)=
{
        {"One", ENUM_ONE},
        {"Two", ENUM_TWO},
        {"Three", ENUM_THREE},
        {"", ENUM_NULL}
};

main{
    // Get enum from string
    SomeEnum i = CEnumMap::findValue("One");

    // Get string from enum
    SomeEnum eee = ENUM_ONE;
    const char* pstr = CEnumMap::findKey(eee);
    ...
}

図書館:

template <class T>
struct CStringPair
{
    const char* _name;
    T _value;
};

template <class T, class Derived>
struct CStringPairHandle
{
    typedef CStringPair<T> CPair;
    static const CStringPair<T> * getPairList(){
        return Derived::implementation();
    }
    static T findValue(const char* name){
        const CStringPair<T> * p = getPairList();
        for (; p->_name[0]!=0; p++)
            if (strcmp(name,p->_name)==0)
                break;
        return p->_value;
    }

    static const char* findKey(T value){
        const CStringPair<T> * p = getPairList();
        for (; p->_name[0]!=0; p++)
            if (strcmp(value,p->_value)==0)
                break;
        return p->_name;
    };
};

#define DEFINE_PAIRLIST(name, type) struct name:public CStringPairHandle<type, name>{ \
    static CPair _pairList[];       \
    static CPair* implementation(){     \
        return _pairList;           \
    }};
#define INIT_PAIRLIST(name) name::CPair name::_pairList[]
1
Ben Lai

を使って std::mapは疑問を投げかけます:マップはどのように初期化されますか?私はむしろ関数を使用したいと思います:

enum E { A, B };

E f( const std::string & s ) {
   if ( s == "A" ) {
      return A;
    }
    else if ( s == "B" ) {
      return B;
    }
    else {
      throw "Your exception here";
    }
}
1
anon

ここからC++リフレクションライブラリを使用する: https://github.com/tapika/cppreflect

次のようなライブラリを含めることができます。

#include "cppreflect/cppreflect.h"

基本的な使用法:

列挙を宣言します:

DECLARE_ENUM( enumName,
    // Prefix for all enums, "" if no prefix used.
    "myenum_",

    myenum_enumValue1,
    myenum_enumValue2,
    myenum_enumValue3 = 5,

    // comment
    myenum_enumValue4
);

変換ロジック:

列挙から文字列へ:

printf( EnumToString(myenum_enumValue3).c_str() );

=> "enumValue3"

文字列から列挙型へ:

enumName value;

if( !StringToEnum("enumValue4", value) )
    printf("Conversion failed...");

=> 

value == myenum_enumValue4

主な/コア機能はここにあります:

https://github.com/tapika/cppreflect/blob/master/cppreflect/enumreflect.h

0
TarmoPikaro

文字列のハッシュを計算して、これを使用できます。

template <typename H, typename E>
E map_hash(H const key, std::initializer_list<std::pair<H, E>> const il)
{
  auto const i(
    std::find_if(il.begin(),
      il.end(),
      [key](auto& p)
      {
        return p.first == key;
      }
    )
  );

  assert(i != il.end());

  return i->second;
}
0
user1095108

文字列を自分で解析し、文字列を値(map<string, enum>のインデックスでもある)と一致させます。

0
dirkgently