Строка для перечисления в С++
Есть ли способ связать строку из текстового файла со значением enum?
Проблема заключается в следующем: у меня есть несколько значений перечисления, которые хранятся в виде строки в текстовом файле, который я прочитал "на лету" при выполнении некоторого условия... Теперь я хочу присвоить значение чтения перечислению.
Каков наиболее эффективный способ сделать это? Это не должен быть самый простой подход.
Ответы
Ответ 1
Вы можете настроить карту, которую вы можете использовать снова и снова:
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");
}
Ответ 2
std::map< string, enumType> enumResolver;
Ответ 3
Я согласен со многими ответами, что std::map
- самое простое решение.
Если вам нужно что-то быстрее, вы можете использовать хэш-карту. Возможно, ваш компилятор уже предлагает один, например hash_map
или предстоящий стандартный unordered_map, или вы можете получить его из boost. Когда все строки известны заранее, идеальное хеширование также можно использовать.
Ответ 4
Использование 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";
}
}
Ответ 5
Посмотрите Boost.Bimap, он обеспечивает двунаправленные ассоциации между двумя наборами значений.
Вы также можете выбрать базовый контейнер.
Ответ 6
Это то, что вы хотите? Инициализация является прямой, и никакой инстанцирования не требуется.
использование:
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[]
Ответ 7
Разберите строку самостоятельно, сопоставьте строку со значением (которое также является индексом для map<string, enum>
.
Ответ 8
Принятый ответ не содержит полного списка. Я добавляю 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)
Ответ 9
Вы можете рассчитать хэш строки, а затем использовать это:
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;
}