在地图中存储不同的数据类型 - 包含类型信息

Ale*_*s G 2 c++ types map

我需要解析并存储一些(但不是太)复杂的流,并且需要以某种方式存储解析的结果.该流本质上包含名称 - 值对,其中values可能对于不同的names 具有不同的类型.基本上,我最终得到一对key(总是字符串)到一对的地图<type, value>.

我从这样的事情开始:

typedef enum ValidType {STRING, INT, FLOAT, BINARY} ValidType;
map<string, pair<ValidType, void*>> Data;
Run Code Online (Sandbox Code Playgroud)

但是我真的不喜欢void*和存储指针.当然,我总是可以将值存储为二进制数据(vector<char>例如),在这种情况下,map最终会存在

map<string, pair<ValidType, vector<char>>> Data;
Run Code Online (Sandbox Code Playgroud)

然而,在这种情况下,我每次需要实际值时都必须解析二进制数据,这在性能方面会非常昂贵.

考虑到我不太担心内存占用(数据量不大),但我担心性能,存储这些数据的正确方法是什么?

理想情况下,我想避免使用boost,因为如果不是更多,这将使最终应用程序的大小增加3倍,我需要将其最小化.

Use*_*ess 5

你正在寻找一个有区别(或标记)的联盟.

Boost.Variant就是一个例子,Boost.Any是另一个例子.您是否确定Boost会将您的最终应用程序大小增加3倍?我原以为变体只是标题,在这种情况下你不需要链接任何库.

如果你真的不能使用Boost,那么实现一个简单的区分联合并不是那么难(一般而且完全正确的联盟是另一回事),至少你知道现在要搜索什么.


为了完整起见,一个天真的歧视联盟可能看起来像:

class DU
{
public:
    enum TypeTag { None, Int, Double };
    class DUTypeError {};
private:
    TypeTag type_;
    union {
        int i;
        double d;
    } data_;

    void typecheck(TypeTag tt) const { if(type_ != tt) throw DUTypeError(); }
public:
    DU() : type_(None) {}
    DU(DU const &other) : type_(other.type_), data_(other.data_) {}
    DU& operator= (DU const &other) {
        type_=other.type_; data_=other.data_; return *this;
    }

    TypeTag type() const { return type_; }
    bool istype(TypeTag tt) const { return type_ == tt; }

#define CONVERSIONS(TYPE, ENUM, MEMBER) \
    explicit DU(TYPE val) : type_(ENUM) { data_.MEMBER = val; } \
    operator TYPE & () { typecheck(ENUM); return data_.MEMBER; } \
    operator TYPE const & () const { typecheck(ENUM); return data_.MEMBER; } \
    DU& operator=(TYPE val) { type_ = ENUM; data_.MEMBER = val; return *this; }

    CONVERSIONS(int, Int, i)
    CONVERSIONS(double, Double, d)
};
Run Code Online (Sandbox Code Playgroud)

现在,有几个缺点:

  • 您不能在联合中存储非POD类型
  • 添加一个类型意味着修改枚举和联合,记住添加一个新CONVERSIONS行(如果没有宏,它会更糟)
  • 你不能使用访问者模式(或者,你必须为它编写自己的调度程序),这意味着客户端代码中有很多switch语句
    • 如果添加类型,这些开关中的每一个都可能还需要更新
    • 如果你没有写访客调度,需要更新,如果你添加一个类型,因此可能每一位参观者
  • 你需要手动重现像内置的C++类型转换规则之类的东西,如果你想做这些事情的算术(即,operator double可以促进Int而不是只处理Double...但只有你手动滚动每个运算符)
  • 我没有完全实现,operator==因为它需要一个开关.如果类型匹配,你不能只记忆两个联合,因为如果double所需的额外空间保持不同的位模式,相同的32位整数仍然可以比较不同

如果你关心它们,可以解决其中一些问题,但这些都是更多的工作.因此,如果可以避免,我倾向于不重新发明这种特殊的车轮.