Пользовательская структура перечисления C ++ для чтения INI-файлов

StackOverflow https://stackoverflow.com/questions/855121

Вопрос

Я пытаюсь создать перечисление, которое имеет строковую метку и значение, и я планирую использовать это для чтения данных из 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) без того, чтобы я на самом деле знал, какой тип перечисления будет использоваться для значения?

Если у вас есть какой-либо код, то это было бы ЗДОРОВО!:)

Это было полезно?

Решение

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

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

Другие советы

Вы смотрели на Повышение.Любое?Он должен делать то, что вы хотите (и если вы потребность чтобы создать свой собственный, вы можете заглянуть в источник для подсказок).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top