2017-04-24 56 views
0

我需要创建一个模块化串行器。我正在使用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实例动态插入所需的字段?

+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; 
}; 

然后在主,把它注册类

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); 
    } 
} 

也许impr我想,但这就是主意。