我需要创建一个模块化序列化器。我正在使用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;
};
然后在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);
}
}
我想也许有所改善,但这就是想法。