views:

485

answers:

2

I'm trying to create an Enum that has a string label and a value and I plan to use this to read stuff from an ini file.

For example in the ini file I might have some double, int or string type values preceded by the tag/name of the value:

SomeFloat = 0.5
SomeInteger = 5
FileName = ../Data/xor.csv

When I read the tag from a file it comes in as a string, so I'd just like to have std::set that keeps all of my values... when I read the tag I can just compare it against the EnumType and if matches the label then I will check the type and do the proper conversion (atoi or just use the string, etc.)

For example:

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:

  1. Can you guys tell me any better solutions? I'm not sure if I'm trying to be too clever for my own good, or if this is really a viable solution.

  2. If my solution is acceptable, then can anybody tell me how I can declare a set of std::set<EnumType<...>> so that it can accept any type (int, double, string) without me actually knowing which type the enum is going to be using for the value?

If you have any code, then it would be GREAT! :)

+1  A: 

Have you looked at Boost.Any? It should do what you want (and if you need to roll your own, you can peek at the source for hints).

Harper Shelby
+1  A: 

If you have limited and very stable set of types, then Boost.Variant may be used. If you going to add support for new types later, then better forget about this method. In this situation solution, based on Boost.Any, or pair of strings will be better.

typedef boost::variant<int, double, std::string> ValueType;
struct EnumType {
std::string label;
ValueType value;
};

Another question is: "How these values will be used later?" If you are going to pass "SomeInteger" to function, accepting int, you still have to run code similar to:

acceptInt( get<int>( v.value ) ); // get may throw

This approach works better when you have uniform processing of 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 );
Konstantin