Строка для перечисления в C ++ - PullRequest
17 голосов
/ 07 апреля 2009

Есть ли способ связать строку из текстового файла со значением перечисления?

Проблема в том, что у меня есть несколько значений enum, хранящихся в виде строки в текстовом файле, который я читаю на лету при выполнении какого-либо условия ... Теперь я хочу присвоить enum значение чтения.

Какой самый эффективный способ сделать это? Это не должен быть самый простой подход.

Ответы [ 9 ]

31 голосов
/ 07 апреля 2009

Вы можете настроить карту, которую вы можете использовать снова и снова:

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");
}
9 голосов
/ 07 апреля 2009
std::map< string, enumType> enumResolver;
3 голосов
/ 08 апреля 2009

Я согласен со многими ответами, что std::map - самое простое решение.

Если вам нужно что-то быстрее, вы можете использовать хэш-карту. Возможно, ваш компилятор уже предлагает такой, например, hash_map или новый стандарт unordered_map, или вы можете получить его из boost . Когда все строки известны заранее, можно также использовать совершенное хеширование .

2 голосов
/ 08 апреля 2009

Посмотрите на Boost.Bimap , он обеспечивает двунаправленную связь между двумя наборами значений. Вы также можете выбрать базовый контейнер.

1 голос
/ 21 сентября 2013

Принятый ответ не содержит полного списка. Я добавляю 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)
1 голос
/ 29 марта 2011

Это то, что вы хотите? Инициализация является прямой, и не требуется никакой реализации.

использование:

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 голос
/ 07 апреля 2009

Использование 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";
    }
}
0 голосов
/ 09 июля 2017

Вы можете вычислить хеш строки и затем использовать это:

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 голосов
/ 07 апреля 2009

Разбор строки самостоятельно, сопоставьте строку со значением (которое также является индексом для map<string, enum>.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...