如何在C++中存储变量数据



我正在创建一个存储特定数据源元数据的类。元数据是以树的形式构建的,与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-if问题。

有人实现或看到过使用标准库的C++变体数据类型更干净的东西吗?

在C++17中,有std::variant

如果你还不能使用它,你可能需要Boost.Variant。std::any提供了一种类似但不同的多态性建模类型(在C++17之前,还有Boost.Any)。

作为一个额外的指针,您可以查找"类型擦除"。

虽然Konrad的答案(使用现有的标准化解决方案)肯定比编写自己的易出错版本更可取,但boost变体有一些开销,尤其是在副本构建和内存方面。

一种常见的定制方法是以下修改的工厂模式:

  1. 为泛型对象创建一个Base接口,该接口还封装对象类型(可以是枚举),也可以使用"typeid"(首选)
  2. 现在使用模板Derived类实现该接口
  3. 创建一个带有签名的模板化create函数的工厂类:

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

这会在堆上内部创建一个Derived<_T>对象,并重新运行一个动态强制转换指针。为您想要实现的每个类专门化这一点。

最后,定义一个包含此Base *指针的Variant包装器,并定义模板get和set函数。这里可以适当地实现getType()isEmpty()、赋值和相等运算符等实用函数。

根据实用程序函数和工厂实现,支持的类将需要支持一些基本功能,如赋值或复制构造。

您还可以使用更具C风格的解决方案,该解决方案在您的系统上有一个双精度大小的void*,再加上您正在使用的类型的枚举。它相当干净,但对于那些对系统的原始字节感到完全满意的人来说,它绝对是一个解决方案。

C++17现在有了std::variant,这正是您想要的。

std::变体

类模板std::variant表示一个类型安全的并集。一std::variant的实例在任何给定时间都保持一个值或在出现错误的情况下-没有值(此状态很难实现,请参见valueless_by_exception)。

与并集一样,如果变量持有某个对象类型T的值,则T的对象表示直接在对象内分配变体本身的表示。变体不允许分配额外的(动态)内存。

尽管这个问题已经回答了很长时间,但为了记录在案,我想提到Qt库中的QVariant也这样做。

因为C++禁止联合包含具有非默认值的类型构造函数或析构函数,最有趣的Qt类不能是用于工会。如果没有QVariant,这将是一个问题QObject::property()和用于数据库工作等的

一个QVariant对象一次保存一个类型()的单个值。(有些类型()是多值的,例如字符串列表。)你可以找出变体的类型T,将其转换为不同的使用convert()类型,使用toT()函数之一获取其值(例如,toSize()),并检查该类型是否可以转换为使用canConvert()的特定类型。

相关内容

  • 没有找到相关文章

最新更新