Ответ 1
Вы можете захотеть Boost.Variant или Boost.Any.
Как дополнительный указатель, вы можете искать "стирание типа".
Я создаю класс, в котором хранятся метаданные об определенном источнике данных. Метаданные структурированы в дереве, очень похожи на структуру 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, если проблема была заявлена выше.
Кто-нибудь реализовал или увидел то, что чище использовать для типа данных типа С++, используя стандартные библиотеки?
Вы можете захотеть Boost.Variant или Boost.Any.
Как дополнительный указатель, вы можете искать "стирание типа".
В то время как ответ Konrad (с использованием существующего стандартизованного решения), безусловно, предпочтительнее писать собственную версию, подверженную ошибкам, вариант повышения имеет некоторые накладные расходы, особенно в построении копии и памяти.
Общим индивидуальным подходом является следующий модифицированный шаблон Factory Pattern:
Derived
.create
с подписью: template <typename _T> Base * Factory::create ();
Это внутренне создает объект Derived<_T>
в куче и перенастраивает динамический указатель. Специализируйте это для каждого класса, который вы хотите реализовать.
Наконец, определите оболочку Variant
, содержащую этот указатель Base *
и определяющий функции get и set шаблона. Функции утилиты, такие как getType()
, isEmpty()
, операторы присваивания и равенства и т.д., Могут быть соответствующим образом реализованы здесь.
В зависимости от функций утилиты и реализации Factory поддерживаемые классы должны поддерживать некоторые базовые функции, такие как назначение или построение копии.
Вы также можете перейти к более C-ish решению, которое будет иметь пустоту * размер двойной в вашей системе, а также перечисление, для которого вы используете. Это разумно чистая, но определенно решение для тех, кто чувствует себя полностью комфортно с необработанными байтами системы.
С++ 17 теперь имеет std::variant
, который именно вы ищете.
Хотя на вопрос был дан ответ в течение длительного времени, для записи я хотел бы упомянуть, что QVariant также делает это.