2017-04-24 11 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私は思っていませんが、それがアイデアです。

関連する問題