我正在创建一个存储有关特定数据源的元数据的类.元数据以树形结构,与XML的结构非常相似.元数据值可以是整数,小数或字符串值.
我很好奇C++是否有一种很好的方法来存储这种情况的变体数据.我希望变体使用标准库,所以我避免使用可用的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.
是否有人使用标准库实现或看到了更清晰的用于C++变体数据类型的东西?
从C++ 17开始,就有了std::variant
.
如果你还不能使用它,你可能想要Boost.Variant.用于建模多态性的类似但不同的类型由std::any
(和,前C++ 17,Boost.Any)提供.
就像一个额外的指针,你可以寻找" 类型擦除 ".
虽然Konrad的答案(使用现有的标准化解决方案)肯定比编写自己的易受攻击的版本更好,但是boost变体有一些开销,特别是在复制构造和内存方面.
常见的定制方法是以下修改的工厂模式:
为通用对象创建Base接口,该接口也封装对象类型(作为枚举)或使用'typeid'(首选).
现在使用模板Derived
类实现接口.
使用create
带签名的模板化函数创建工厂类:
template
这会Derived<_T>
在堆内部创建一个对象,并返回一个动态转换指针.专门针对您想要实现的每个课程.
最后,定义一个Variant
包含此Base *
指针的包装器,并定义模板get和set函数.这里可以适当地实现诸如getType()
,isEmpty()
赋值和相等运算符等实用函数.
根据实用程序功能和工厂实现,受支持的类将需要支持一些基本功能,如赋值或复制构造.
您还可以使用更多C-ish解决方案,该系统将具有系统上双倍大小的void*,以及您正在使用的类型的枚举.它相当干净,但对于那些对系统的原始字节感到完全满意的人来说绝对是一个解决方案.
C++ 17现在std::variant
正是您正在寻找的.
的std ::变种