C ++ Custom Enum Struct для чтения файлов INI - PullRequest
0 голосов
/ 13 мая 2009

Я пытаюсь создать Enum, который имеет строковую метку и значение, и я планирую использовать это для чтения содержимого из INI-файла.

Например, в ini-файле у меня могут быть значения типа double, int или string, перед которыми стоит тег / имя значения:

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

Когда я читаю тег из файла, он появляется как string, поэтому я просто хотел бы иметь std::set, который хранит все мои значения ... когда я читаю тег, я могу просто сравнить его против EnumType и, если совпадает с меткой, я проверю тип и выполню правильное преобразование (atoi или просто использую строку и т. д.)

Например:

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;
    }
};

У меня есть несколько вопросов:

  1. Не могли бы вы, ребята, сказать мне какие-нибудь лучшие решения? Я не уверен, пытаюсь ли я быть слишком умным для собственного блага или это действительно жизнеспособное решение.

  2. Если моё решение приемлемо, то кто-нибудь может сказать мне, как я могу объявить набор std::set<EnumType<...>>, чтобы он мог принимать любой тип (int, double, string), и я не знал, какой тип перечисления будет использовать для значения?

Если у вас есть какой-либо код, это было бы здорово! :)

Ответы [ 2 ]

1 голос
/ 13 мая 2009

Если у вас ограниченный и очень стабильный набор типов, то можно использовать Boost.Variant . Если вы собираетесь добавить поддержку новых типов позже, тогда лучше об этом методе забыть. В этой ситуации решение на основе Boost.Any или пары строк будет лучше.

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

Другой вопрос: «Как эти значения будут использоваться позже?» Если вы собираетесь передать «SomeInteger» в функцию, принимая int, вам все равно придется запустить код, подобный следующему:

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

Этот подход работает лучше, когда у вас единообразная обработка фиксированного набора типов:

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 );
1 голос
/ 13 мая 2009

Вы смотрели на Boost.Any ? Он должен делать то, что вы хотите (и если вам нужно , чтобы бросить свой собственный, вы можете посмотреть на источник подсказок).

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