Is there a way to associate a string from a text file with an enum value?
The problem is: I have a few enum values stored as string in a text file which I read on the fly on meeting some condition... Now I want to assign the read value to an enum.
What is the most effective way to do so? It doesn't need to be the simplest approach.
You can set up a map that you can use over and over:
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");
}
std::map< string, enumType> enumResolver;
I agree with many of the answers that std::map is the easiest solution.
If you need something faster, you can use a hash map. Perhaps your compiler already offers one, such as hash_map or the upcoming standard unordered_map, or you can get one from boost. When all the strings are known ahead of time, perfect hashing can be used as well.
Accepted answer doesn't contain full listing. I'm adding EnumParser.h which I created from the accepted answer, hope it can help
#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;
}
};
Usage is simple:
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;
}
use:
EnumParser<FieldType> fieldTypeParser;
FieldType val = fieldTypeParser.ParseSomeEnum(stringValue)
Look at Boost.Bimap, it provides bidirectional associations between two sets of values.
You can also choose the underlying container.
Using a std::map raises the question: how does the map get initialised? I would rather use a function:
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";
}
}
Is this what you want? The initialization is straight, and no instantiation is needed.
usage:
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);
...
}
library:
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[]
Parse the string yourself, match the string with a value (which is also an index to a map<string, enum>.
You can calculate the hash of the string and then use this:
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;
}
Using C++ reflection library from here: https://github.com/tapika/cppreflect
You can - include library like this:
#include "cppreflect/cppreflect.h"
Basic usage:
Declare enumeration:
DECLARE_ENUM( enumName,
// Prefix for all enums, "" if no prefix used.
"myenum_",
myenum_enumValue1,
myenum_enumValue2,
myenum_enumValue3 = 5,
// comment
myenum_enumValue4
);
Conversion logic:
From enumeration to string:
printf( EnumToString(myenum_enumValue3).c_str() );
=> "enumValue3"
From string to enumeration:
enumName value;
if( !StringToEnum("enumValue4", value) )
printf("Conversion failed...");
=>
value == myenum_enumValue4
Main / core functionality resides in here:
https://github.com/tapika/cppreflect/blob/master/cppreflect/enumreflect.h
Related
Is it better to do:
class Foo{
std:string option1(MY_ENUM type){
static const std:string f1 = "a";
static const std:string f2 = "b";
static const std:string f3 = "c";
// ...
switch (type) {
case (TYPE_1):{
return f1;
break;
}
case (TYPE_2):{
return f2;
break;
}
// ...
}
}
Or do this:
class Foo {
private:
const std:string f1 = "a";
const std:string f2 = "b";
const std:string f3 = "c";
public:
std:string option1(MY_ENUM type){
// ...
switch (type){
case (TYPE_1):{
return f1;
break;
}
case (TYPE_2):{
return f2;
break;
}
// ...
}
}
Likewise I would do something similar to convert the enum to the string.
Is it better to keep the strings as static const within the function, or as private within the class ?
- No one else is going to edit the class but me.
- It doesn't really matter if any other functions inside the class know what the values of the strings are, and since it is const they can't modify it anyway.
Which is cheaper and has less overhead at runtime and during compilation ? Which is a better practice ?
Cheaper would be not to use std::string at all since it will likely require run-time initialization and also use a lookup table to translate from enum to string:
const char *enumToStr(MY_ENUM type) {
static const char *const names[] = { "a", "b", "c" };
if (type < sizeof(names) / sizeof(names[0]))
return names[type];
return nullptr;
}
Unfortunately you can't use this kind of trick for a reverse conversion. Also this assumes that your enumerators have contiguous numerical values and you should be careful when adding or reordering your enum's values.
As for "where to put these values" question, it doesn't really matter from the "overhead" point of view as long as this array is static or global. I would suggest putting it into a global variable within an anonymous namespace inside the *.cpp file that defines these conversion functions, so that it can be used for both functions but isn't visible outside of this translation unit:
namespace {
const char *const names[] = ...;
}
The most common implementation in c++ is to setup a map for this:
#include <iostream>
#include <unordered_map>
#include <string>
enum MY_ENUM {
TYPE_1
, TYPE_2 = 42 // Mind the gap please!
};
const char* const option1(MY_ENUM type) {
static std::unordered_map<MY_ENUM, const char* const> enum2StringMap =
{ { TYPE_1, "a" }
, { TYPE_2, "b" }
// ...
};
if(enum2StringMap.find(type) == enum2StringMap.end()) {
// throw exception or do whatever to indicate an error
return "Invalid enum value";
}
return enum2StringMap[type];
}
For the vice versa option you might need to take the burden to keep a second map, and synchronize it with the 1st one:
MY_ENUM option1(const std::string& s) {
static std::unordered_map<std::string, MY_ENUM> string2EnumgMap =
{ { "a" , TYPE_1 }
, { "b" , TYPE_2 }
// ...
};
if(string2EnumgMap.find(s) == string2EnumgMap.end()) {
// throw exception or do whatever to indicate an error
}
return string2EnumgMap[s];
}
Another option making the synchonization easier (but may have other drawbacks regarding performance) could be using a boost::bimap.
int main() {
std::cout << option1(TYPE_1) << std::endl;
std::cout << option1(TYPE_2) << std::endl;
std::cout << option1("a") << std::endl;
std::cout << option1("b") << std::endl;
}
Output:
a
b
0
42
Not as "cheap" as #r3musn0x proposed solution, but eliminates the concerns mentioned in #KonstantinL's comment.
There will be a little overhead when the maps are initialized at first access, but any foolowing up search might be optimized to be O(log n) vs. O(n) time complexity.
See a working online demo.
A variation on #KonstantinL's approach; I too think you would be best served by avoiding std::strings to the extent that you can. But I would also like to avoid maps...
class Foo {
public:
enum MY_ENUM {
TYPE_1,
TYPE_2
};
protected:
using pair_type = std::pair<MY_ENUM, const char*>;
// the following will work with C++17:
// See also: https://stackoverflow.com/q/6114067/1593077
// about initializing std::arrays without specifying the length.
static constexpr const auto names_and_codes = std::array {
pair_type { TYPE_1, "a" },
pair_type { TYPE_2, "b" },
};
public:
static const char* name_of(MY_ENUM t) noexcept
{
auto iter = std::find_if(names_and_codes.begin(), names_and_codes.end(),
[&t](const auto& pair) { return pair.first == t; }
);
if (iter != names.end()) { return iter->second; }
return nullptr; // Or handle the not-found case differently
}
static MY_ENUM code_for(const char* name) noexcept
{
auto iter = std::find_if(names_and_codes.begin(), names_and_codes.end(),
[&t](const auto& pair) { return std::strcmp(pair.second, name) == 0; }
);
if (iter != names.end()) { return iter->first; }
return MY_ENUM{-1}; // Or handle the not-found case differently
}
// more code for class Foo
}
This uses a static array instead of a map; linear search in contiguous memory is faster than binary search on trees on with heap-allocated nodes - for a limited number of values, which seems to be the case for you. Also - no use of the heap at all here.
Notes:
This fixed-size-array-backed "map" can be factored out and made generic, in a separate header. It comes in useful sometimes.
If your array is sorted, you can make one of the searches binary.
If I give 10 means it should print it is a integer
If I give 10.2 means it should print it is a float
If I give 'a' means it should print it is a char
Read the input as a std::string first.
Then, pass the string to std::stoi(), and if it consumes the whole string without error, print the resulting integer.
Otherwise, pass the string to std::stof() , and if it consumes the whole string without error, print the resulting float.
Otherwise, print the string as-is.
You can use type_traits and template specialization to achieve this. Please see this example for more info:-
#include <iostream>
#include <type_traits>
template<typename T>
struct is_integer{
static const bool value = false;
};
template<>
struct is_integer<int>{
static const bool value = true;
};
template<typename T>
struct is_char{
static const bool value = false;
};
template<>
struct is_char<char>{
static const bool value = true;
};
template<typename T>
void printType(T t){
if(is_integer<T>::value)
{
std::cout<<"Value is integer"<<std::endl;
}
else if(is_char<T>::value)
{
std::cout<<"Value is char"<<std::endl;
}
else if(std::is_floating_point<T>::value)
{
std::cout<<"Value is float"<<std::endl;
}
}
int main()
{
int i = 10;
char j = 'a';
float k = 10.2f;
printType(i);
printType(j);
printType(k);
return 0;
}
Say I have an object defined like this:
struct Something
{
int attribute1;
string attribute2;
}
I then have a File that contains a bunch of information that should be applied to a created object. However, the attribute name that it should be applied to is also stored in the file. In other words, the text file would contain two values like so:
123, "attribute1"
I need a way to reference an object's attribute by a string. Something like Something[variable_holding_attribute_name] would be perfect!
Is there any way of doing this in C++? Please also note that I can't use a map, as the object contains more than 1 data type.
Just because your struct uses different data types does not mean you cannot use a std::map to access them, because you can. Try something like this:
struct Something
{
int attribute1;
std::string attribute2;
};
void set_attr1(Something &obj, const std::string &value)
{
std::istringstream iss(value);
iss >> obj.attribute1;
}
void set_attr2(Something &obj, const std::string &value)
{
obj.attribute2 = value;
};
typedef void (*set_func)(Something&, const std::string&);
std::map<std::string, set_func> m;
m["attribute1"] = &set_attr1;
m["attribute2"] = &set_attr2;
...
Something obj;
std::string value = ...; // "123"
std::string name = ...; // "attribute1"
m[name](obj, value);
/*
Or safer:
std::map<std::string, set_func>::iterator iter = m.find(name);
if (iter != m.end())
iter->second(obj, value);
*/
If you want something a little more flexible that allows you to re-use a given function for multiple fields of the same data type, even re-use the same functions for maps of different structs, you can do this instead:
template<typename ObjType, typename MemType, MemType ObjType::*member>
void set_member(ObjType &obj, const std::string &value)
{
std::istringstream iss(value);
iss >> obj.*member;
}
template<typename ObjType, std::string ObjType::*member>
void set_str_member(ObjType &obj, const std::string &value)
{
obj.*member = value;
}
template<typename ObjType>
struct set_member_hlpr
{
typedef void (*func_type)(ObjType&, const std::string&);
};
struct Something
{
int attribute1;
std::string attribute2;
};
std::map<std::string, set_func_hlpr<Something>::func_type > m;
m["attribute1"] = &set_member<Something, int, &Something::attribute1>
// you can use set_member() for Something::attribute2, but
// std::istringstream will split the input value on whitespace,
// which may not be desirable. If you want to preserve the whole
// value, use set_str_member() instead..
m["attribute2"] = &set_str_member<Something, &Something::attribute2>;
...
Something obj;
std::string value = ...; // "123"
std::string name = ...; // "attribute1"
m[name](obj, value);
/*
Or safer:
std::map<std::string, set_func>::iterator iter = m.find(name);
if (iter != m.end())
iter->second(obj, value);
*/
Can I use C++ template classes to differentiate object types? Or what should I use?
Eg. I have a class Synonym and it can be of type Statement, Procedure, etc for example. I have functions that accepts these synonyms and evaluates them depending on its type. So I was thinking it will be nice if I can do something like:
enum Types { Statement, Procedure, Variable, ... };
template <typename Types>
class Synonym { ... }
void evaluate(Synonym<Statement> s, Synonym<Variable> v) { do something }
^ so that I can do this ... instead of checking the type in function like:
void evaluate(Synonym s, Synonym v) {
assert(s.type == Statement);
assert(v.type == Variable);
// also would like to eliminate things like: (if possible)
switch(s.type) {
case XXX: doSomething ...
case YYY: doAnotherThing ...
}
}
You could create a function template and then specialize on that template
template<typename Type>
void evaluate (Type t) {}
template<>
void evaluate<Statement>( Statement s)
{}
This way, when you pass a Statement it will pick that overload, and you can do different behaviors depending on type.
I think using a variant and visitor pattern would be suited. Have a look at Boost.Variant here: http://www.boost.org/doc/libs/1_51_0/doc/html/variant.html, the last example (also below but expanded) shows a visitor implementation. There are also other variant and visitor implementations. std::any and loki are also options. I personally like loki but that is probably just because I'm a huge fan of Alexandrescu.
#include "boost/variant.hpp"
#include <iostream>
class ToLengthVisitor : public boost::static_visitor<int>
{
public:
int operator()(int i) const
{
return i;
}
int operator()(const std::string & str) const
{
return str.length();
}
int operator()(const char * str) const
{
const char * temp = str;
while(*temp != '\0') temp++;
return temp-str;
}
};
int main()
{
typedef boost::variant< int, std::string, const char * > MyVariant;
MyVariant u(std::string("hello world"));
std::cout << u; // output: hello world
MyVariant cu(boost::get<std::string>(u).c_str());
int result = boost::apply_visitor( ToLengthVisitor(), u );
std::cout << result; // output: 11 (i.e., length of "hello world")
result = boost::apply_visitor( ToLengthVisitor(), cu );
std::cout << result; // output: 11 (i.e., length of "hello world")
}
Is there a generic way to cast int to enum in C++?
If int falls in range of an enum it should return an enum value, otherwise throw an exception. Is there a way to write it generically? More than one enum type should be supported.
Background: I have an external enum type and no control over the source code. I'd like to store this value in a database and retrieve it.
The obvious thing is to annotate your enum:
// generic code
#include <algorithm>
template <typename T>
struct enum_traits {};
template<typename T, size_t N>
T *endof(T (&ra)[N]) {
return ra + N;
}
template<typename T, typename ValType>
T check(ValType v) {
typedef enum_traits<T> traits;
const T *first = traits::enumerators;
const T *last = endof(traits::enumerators);
if (traits::sorted) { // probably premature optimization
if (std::binary_search(first, last, v)) return T(v);
} else if (std::find(first, last, v) != last) {
return T(v);
}
throw "exception";
}
// "enhanced" definition of enum
enum e {
x = 1,
y = 4,
z = 10,
};
template<>
struct enum_traits<e> {
static const e enumerators[];
static const bool sorted = true;
};
// must appear in only one TU,
// so if the above is in a header then it will need the array size
const e enum_traits<e>::enumerators[] = {x, y, z};
// usage
int main() {
e good = check<e>(1);
e bad = check<e>(2);
}
You need the array to be kept up to date with e, which is a nuisance if you're not the author of e. As Sjoerd says, it can probably be automated with any decent build system.
In any case, you're up against 7.2/6:
For an enumeration where emin is the
smallest enumerator and emax is the
largest, the values of the enumeration
are the values of the underlying type
in the range bmin to bmax, where bmin
and bmax are, respectively, the
smallest and largest values of the
smallest bit-field that can store emin
and emax. It is possible to define an
enumeration that has values not
defined by any of its enumerators.
So if you aren't the author of e, you may or may not have a guarantee that valid values of e actually appear in its definition.
Ugly.
enum MyEnum { one = 1, two = 2 };
MyEnum to_enum(int n)
{
switch( n )
{
case 1 : return one;
case 2 : return two;
}
throw something();
}
Now for the real question. Why do you need this? The code is ugly, not easy to write (*?) and not easy to maintain, and not easy to incorporate in to your code. The code it telling you that it's wrong. Why fight it?
EDIT:
Alternatively, given that enums are integral types in C++:
enum my_enum_val = static_cast<MyEnum>(my_int_val);
but this is even uglier that above, much more prone to errors, and it won't throw as you desire.
If, as you describe, the values are in a database, why not write a code generator that reads this table and creates a .h and .cpp file with both the enum and a to_enum(int) function?
Advantages:
Easy to add a to_string(my_enum) function.
Little maintenance required
Database and code are in synch
No- there's no introspection in C++, nor is there any built in "domain check" facility.
What do you think about this one?
#include <iostream>
#include <stdexcept>
#include <set>
#include <string>
using namespace std;
template<typename T>
class Enum
{
public:
static void insert(int value)
{
_set.insert(value);
}
static T buildFrom(int value)
{
if (_set.find(value) != _set.end()) {
T retval;
retval.assign(value);
return retval;
}
throw std::runtime_error("unexpected value");
}
operator int() const { return _value; }
private:
void assign(int value)
{
_value = value;
}
int _value;
static std::set<int> _set;
};
template<typename T> std::set<int> Enum<T>::_set;
class Apples: public Enum<Apples> {};
class Oranges: public Enum<Oranges> {};
class Proxy
{
public:
Proxy(int value): _value(value) {}
template<typename T>
operator T()
{
T theEnum;
return theEnum.buildFrom(_value);
}
int _value;
};
Proxy convert(int value)
{
return Proxy(value);
}
int main()
{
Apples::insert(4);
Apples::insert(8);
Apples a = convert(4); // works
std::cout << a << std::endl; // prints 4
try {
Apples b = convert(9); // throws
}
catch (std::exception const& e) {
std::cout << e.what() << std::endl; // prints "unexpected value"
}
try {
Oranges b = convert(4); // also throws
}
catch (std::exception const& e) {
std::cout << e.what() << std::endl; // prints "unexpected value"
}
}
You could then use code I posted here to switch on values.
You should not want something like what you describe to exist, I fear there are problems in your code design.
Also, you assume that enums come in a range, but that's not always the case:
enum Flags { one = 1, two = 2, four = 4, eigh = 8, big = 2000000000 };
This is not in a range: even if it was possible, are you supposed to check every integer from 0 to 2^n to see if they match some enum's value?
If you are prepared to list your enum values as template parameters you can do this in C++ 11 with varadic templates. You can look at this as a good thing, allowing you to accept subsets of the valid enum values in different contexts; often useful when parsing codes from external sources.
Perhaps not quite as generic as you'd like, but the checking code itself is generalised, you just need to specify the set of values. This approach handles gaps, arbitrary values, etc.
template<typename EnumType, EnumType... Values> class EnumCheck;
template<typename EnumType> class EnumCheck<EnumType>
{
public:
template<typename IntType>
static bool constexpr is_value(IntType) { return false; }
};
template<typename EnumType, EnumType V, EnumType... Next>
class EnumCheck<EnumType, V, Next...> : private EnumCheck<EnumType, Next...>
{
using super = EnumCheck<EnumType, Next...>;
public:
template<typename IntType>
static bool constexpr is_value(IntType v)
{
return v == static_cast<typename std::underlying_type<EnumType>::type>(V) || super::is_value(v);
}
EnumType convert(IntType v)
{
if (!is_value(v)) throw std::runtime_error("Enum value out of range");
return static_cast<EnumType>(v);
};
enum class Test {
A = 1,
C = 3,
E = 5
};
using TestCheck = EnumCheck<Test, Test::A, Test::C, Test::E>;
void check_value(int v)
{
if (TestCheck::is_value(v))
printf("%d is OK\n", v);
else
printf("%d is not OK\n", v);
}
int main()
{
for (int i = 0; i < 10; ++i)
check_value(i);
}
C++0x alternative to the "ugly" version, allows for multiple enums. Uses initializer lists rather than switches, a bit cleaner IMO. Unfortunately, this doesn't work around the need to hard-code the enum values.
#include <cassert> // assert
namespace // unnamed namespace
{
enum class e1 { value_1 = 1, value_2 = 2 };
enum class e2 { value_3 = 3, value_4 = 4 };
template <typename T>
int valid_enum( const int val, const T& vec )
{
for ( const auto item : vec )
if ( static_cast<int>( item ) == val ) return val;
throw std::exception( "invalid enum value!" ); // throw something useful here
} // valid_enum
} // ns
int main()
{
// generate list of valid values
const auto e1_valid_values = { e1::value_1, e1::value_2 };
const auto e2_valid_values = { e2::value_3, e2::value_4 };
auto result1 = static_cast<e1>( valid_enum( 1, e1_valid_values ) );
assert( result1 == e1::value_1 );
auto result2 = static_cast<e2>( valid_enum( 3, e2_valid_values ) );
assert( result2 == e2::value_3 );
// test throw on invalid value
try
{
auto result3 = static_cast<e1>( valid_enum( 9999999, e1_valid_values ) );
assert( false );
}
catch ( ... )
{
assert( true );
}
}