Подтвердить что ты не робот

Вариант С++

Я создаю класс, в котором хранятся метаданные об определенном источнике данных. Метаданные структурированы в дереве, очень похожи на структуру XML. Значения метаданных могут быть целыми, десятичными или строковыми значениями.

Мне любопытно, есть ли хороший способ в С++ хранить варианты данных для такой ситуации. Я бы хотел, чтобы вариант использовал стандартные библиотеки, поэтому я избегаю доступных типов COM, Ole и SQL VARIANT.

Мое текущее решение выглядит примерно так:

enum MetaValueType
{
    MetaChar,
    MetaString,
    MetaShort,
    MetaInt,
    MetaFloat,
    MetaDouble
};

union MetaUnion
{
    char cValue;
    short sValue;
    int iValue;
    float fValue;
    double dValue;
};

class MetaValue
{
...
private:
    MetaValueType ValueType;
    std::string StringValue;
    MetaUnion VariantValue;
};

Класс MetaValue имеет различные функции Get для получения значения хранимого в данный момент значения, но в итоге он делает каждый запрос для значения большим блоком if/else if, чтобы выяснить, какое значение я ищу.

Я также изучил сохранение значения как только строки и выполнение преобразований для получения разных типов вариантов, но, насколько я видел, это приводит к кучке внутреннего анализа строк и обработки ошибок, который не является довольно, открывает большую старую возможность прецизионных и проблем с потерями данных с плавающей запятой и по-прежнему не устраняет запрос if/else, если проблема была заявлена ​​выше.

Кто-нибудь реализовал или увидел то, что чище использовать для типа данных типа С++, используя стандартные библиотеки?

4b9b3361

Ответ 1

Вы можете захотеть Boost.Variant или Boost.Any.

Как дополнительный указатель, вы можете искать "стирание типа".

Ответ 2

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

Общим индивидуальным подходом является следующий модифицированный шаблон Factory Pattern:

  • Создайте базовый интерфейс для общего объекта, который также инкапсулирует тип объекта (либо как перечисление), либо использует "typeid" (предпочтительно).
  • Теперь реализуем интерфейс с помощью шаблона Derived.
  • Создайте класс Factory с шаблонизированной функцией create с подписью:

template <typename _T> Base * Factory::create ();

Это внутренне создает объект Derived<_T> в куче и перенастраивает динамический указатель. Специализируйте это для каждого класса, который вы хотите реализовать.

Наконец, определите оболочку Variant, содержащую этот указатель Base * и определяющий функции get и set шаблона. Функции утилиты, такие как getType(), isEmpty(), операторы присваивания и равенства и т.д., Могут быть соответствующим образом реализованы здесь.

В зависимости от функций утилиты и реализации Factory поддерживаемые классы должны поддерживать некоторые базовые функции, такие как назначение или построение копии.

Ответ 3

Вы также можете перейти к более C-ish решению, которое будет иметь пустоту * размер двойной в вашей системе, а также перечисление, для которого вы используете. Это разумно чистая, но определенно решение для тех, кто чувствует себя полностью комфортно с необработанными байтами системы.

Ответ 4

С++ 17 теперь имеет std::variant, который именно вы ищете.

std:: variant

Ответ 5

Хотя на вопрос был дан ответ в течение длительного времени, для записи я хотел бы упомянуть, что QVariant также делает это.