C ++ Custom Enum Struct for reading INI files
I am trying to create an Enum that has a string label and value and I am planning on using that to read files from an ini file.
For example, in an ini file, I can have values of type double
, int
or string
, preceded by a tag / value name:
SomeFloat = 0.5
SomeInteger = 5
FileName = ../Data/xor.csv
When I read a tag from a file, it comes as string
, so I just want to have std::set
that stores all my values ... when I read the tag, I can just compare it against EnumType
, and if it matches the tag, I check the type and do the correct conversion ( atoi or just use a string, etc.).
For instance:
EnumType<int> someInteger;
someInteger.label = "SomeInteger";
someInteger.type = INT;
std::set<EnumType> myValues;
//
// populate the set
myValues.insert(someInteger);
//
void ProcessTagAndValue(const std::string &tag, const std::string &value)
{
switch(myValues[tag].type)
{
case INT:
myValues[tag].value = atoi(value);
break;
case DOUBLE:
//
break;
case STRING:
myValues[tag].value = value;
break;
default:
break;
}
}
enum ValueType{INT,DOUBLE,STRING];
template <class T>
struct EnumType{
std::string label;
ValueType type;
T value;
bool operator==(const EnumType &other) const {
return this->label == other.label;
}
bool operator==(const T& other ) const
{
return this->value == other;
}
T& operator=(const T& p)
{
value = p;
return value;
}
EnumType& operator=(const EnumType& p)
{
if (this != &p) { // make sure not same object
this->label = p.label;
this->value = p.value;
}
return *this;
}
};
I have several questions:
-
Can you guys tell me the best solutions? I'm not sure if I'm trying to be too smart for myself, or if this is a really viable solution.
-
If my solution is acceptable, then someone will tell me how can I declare a set
std::set<EnumType<...>>
so that it can take on any type (int, double, string) without me actually knowing what type the enumeration will be for the value?
If you have the code then it will be GREAT! :)
a source to share
If you have a limited and very stable set of types, then you can use Boost.Variant . If you add support for new types later, you better forget about this method. In this situation, a solution based on Boost.Any or a couple of lines would be better.
typedef boost::variant<int, double, std::string> ValueType;
struct EnumType {
std::string label;
ValueType value;
};
Another question: "How will these values be used later?" If you are going to pass "SomeInteger" to work while accepting an int, you still need to run code similar to:
acceptInt( get<int>( v.value ) ); // get may throw
This approach works best if you have a consistent handling of a fixed set of types:
class processValue : public boost::static_visitor<>
{
public:
void operator()(int i) const
{
acceptInt( i );
}
void operator()(double d) const
{
acceptDouble( d );
}
void operator()(const std::string & str) const
{
acceptString( str );
}
};
boost::apply_visitor( processValue(), v.value );
a source to share