C ++ Variant

时间:2008-10-16 15:09:34

标签: c++ variant

我正在创建一个存储有关特定数据源的元数据的类。元数据以树形结构,与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 ++变体数据类型的东西?

5 个答案:

答案 0 :(得分:30)

从C ++ 17开始,有std::variant

如果您还不能使用它,您可能需要Boost.Variant。用于建模多态性的类似但不同的类型由std::any(以及前C ++ 17,Boost.Any)提供。

作为附加指针,您可以查找“type erasure”。

答案 1 :(得分:12)

虽然Konrad的答案(使用现有的标准化解决方案)肯定比编写自己的易受错误的版本更好,但是boost变体有一些开销,特别是在复制构造和内存中。

常见的自定义方法是以下修改后的工厂模式:

  1. 为通用对象创建一个Base接口,该接口也封装对象类型(作为枚举)或使用'typeid'(最好)。
  2. 现在使用模板Derived类实现接口。
  3. 使用带签名的模板化create函数创建工厂类:
  4. template <typename _T> Base * Factory::create ();

    这会在堆内部创建一个Derived<_T>对象,并返回一个动态转换指针。专门针对您想要实施的每个课程。

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

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

答案 2 :(得分:9)

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

答案 3 :(得分:7)

C ++ 17现在有std::variant,这正是您正在寻找的。

std::variant

答案 4 :(得分:4)

虽然这个问题已经回答了很长时间,但是为了记录,我想提一下QVariant也这样做。