模板参数包序列化

时间:2017-04-24 10:24:54

标签: c++

我需要创建一个模块化序列化器。我正在使用msgpack。

因此,一个简单的表单就像这样构建:

enum class FieldId
{
  Time,
  Pressure
};

struct TimeFieldConfig
{
  typedef long long DataType;
  const static FieldId id = FieldId::Time;
}

struct PressureFieldConfig
{
  typedef double DataType;
  const static FieldId id = FieldId::Pressure;
}

struct BaseField
{
  virtual void dump(std::ofstream &buffer) const = 0;
};

template<class T>
struct Field : BaseField
{
  void dump(std::ofstream &buffer)
  {
    msgpack::pack(buffer, values);
  }
  std::vector<typename T::DataType> values;
}

struct Recorder
{
    template <class T>
    void insertField()
    {
        data.insert_or_assign(T::id, new Field<T>);
    }

    template <class T>
    void add(const typename T::DataType &v)
    {
        if (data.find(T::id) != data.cend())
            reinterpret_cast<Field<T> *>(data[T::id])->add(v);
    }

    void dump(const std::string fpath)
    {
        std::ofstream outFile;
        outFile.open(fpath, std::ios::binary);

        // headers
        std::vector<int> keys;
        for (const auto &k : data)
            keys.push_back(static_cast<int>(k.first));
        msgpack::pack(outFile, keys);

        // values
        for (const auto &k : data)
            k.second->dump(outFile);

        outFile.close();
    }

    std::map<FieldId, BaseField *> data;
}

int main(int arc, char* argv[])
{
  Recorder r;
  r.insertField<TimeFieldConfig>();
  r.insertField<PressureFieldConfig>();

  /* add data ... */
  r.dump("data.dat");
}

转储工作正常,所有数据和标头都存在。 现在我想加载记录的数据。

我的问题是如何创建动态插入所需字段的Recorder实例?

1 个答案:

答案 0 :(得分:0)

我回答自己,以防它可能会有所帮助。

我想要创建的是名为注册表模式。 这就是我做的方式。

// may be a singleton
class FieldFactory
{
public:
    FieldFactory()
    {
    }
    ~FieldFactory()
    {
    }

    template <class T>
    void registerField()
    {
        creators.insert_or_assign(T::id, &Field<T>::creator);
    }

    BaseField *create(FieldId fid)
    {
        return creators[fid]();
    }

private:
    typedef std::function<BaseField *()> FieldCreator;
    std::map<FieldId, FieldCreator> creators;
};

然后在main中,将其命名为注册类

FieldFactory ff;
ff.registerField<TimeFieldConfig>();
ff.registerField<PressureFieldConfig>();

在字段模板类中添加:

static BaseField *creator()
{
  return new Field<T>();
}

Recorder类中创建一个加载函数:

void reload(const std::string &filePath)
{
    std::ifstream inFile;
    inFile.open(filePath, std::ios::binary);

    std::vector<char> buffer((std::istreambuf_iterator<char>(inFile)), (std::istreambuf_iterator<char>()));
    inFile.close();

    // headers
    std::size_t off = 0;
    std::vector<int> keys;

    msgpack::object_handle result;
    msgpack::unpack(result, buffer.data(), buffer.size(), off);
    result.get().convert(keys);

    // create fields
    for (auto k : keys)
    {
        FieldId fid = static_cast<FieldId>(k);
        data.insert_or_assign(fid, m_ff->create(fid));
    }

    // values
    for (auto k : keys)
    {
        msgpack::object_handle oh;
        msgpack::unpack(oh, buffer.data(), buffer.size(), off);

        FieldId fid = static_cast<FieldId>(k);
        if (data.find(fid) != data.cend())
            data[fid]->reload(oh);
    }
}

我想也许有所改善,但这就是想法。