C++11 使用c+自动进行结构反序列化/转换+;模板
我有一些C++11 使用c+自动进行结构反序列化/转换+;模板,c++11,templates,c++14,C++11,Templates,C++14,我有一些C数据接口(pod结构),每个接口都有不同的版本,每个版本都有反序列化功能。 (完整代码如下) 用户类型: typedef struct sInterface_v1_t { int i; }Interface_v1_t; typedef struct sInterface_v2_t { int i; int j; }Interface_v2_t; typedef struct sInterface_v3_t { int j; float u; }Interface
C
数据接口(pod结构),每个接口都有不同的版本,每个版本都有反序列化功能。
(完整代码如下)
用户类型:
typedef struct sInterface_v1_t {
int i;
}Interface_v1_t;
typedef struct sInterface_v2_t {
int i;
int j;
}Interface_v2_t;
typedef struct sInterface_v3_t {
int j;
float u;
}Interface_v3_t;
// latest version
typedef Interface_v3_t Interface_t;
void Interface_v1_deserialize(std::stringstream& io_str, Interface_v1_t* o_d)
{
io_str >> o_d->i;
}
void Interface_v2_deserialize(std::stringstream& io_str, Interface_v2_t* o_d)
{
io_str >> o_d->i;
io_str >> o_d->j;
}
void Interface_v3_deserialize(std::stringstream& io_str, Interface_v3_t* o_d)
{
io_str >> o_d->j;
io_str >> o_d->u;
}
序列化的数据流对数据类型和版本号进行编码,因此易于分派
// type interfaceversion data...
std::string data_1 = "I 1 5";
std::string data_2 = "I 2 7 2";
std::string data_3 = "I 3 1 3.54";
我想创建一个总是输出最新类型的泛型反序列化
最后,反序列化代码应该如下所示:
std::stringstream s(data_1); // or data_2 or data_3
s >> ts; // remove type from string (type dispatching will be later one level above)
Interface_t i = { 0 };
Interface_Deserializer<Interface_t>::instance().deserialize(s, &i);
我创建了一组可以实现这一点的模板(见下面的完整列表),但是用户必须创建一些锅炉板代码才能让它们工作
用户锅炉板
template <>
struct InterfaceVersionHelper<Interface_t, 1> :InterfaceVersionHelperBase<Interface_t, Interface_v1_t, 1, &Interface_v1_deserialize>
{};
template <>
struct InterfaceVersionHelper<Interface_t, 2> :InterfaceVersionHelperBase<Interface_t, Interface_v2_t, 2, &Interface_v2_deserialize>
{};
template <>
struct InterfaceVersionHelper<Interface_t, 3> :InterfaceVersionHelperBase<Interface_t, Interface_v3_t, 3, &Interface_v3_deserialize>
{};
static bool r1 = []() {
InterfaceVersionHelper<Interface_t, 1>::registerMe();
InterfaceVersionHelper<Interface_t, 2>::registerMe();
InterfaceVersionHelper<Interface_t, 3>::registerMe();
return true;
}();
template <>
struct LatestInterface<Interface_t> :public Interface_LatestVersion<Interface_t, 3> {};
template <>
struct InterfaceVersionHelper<Interface_t, 1> :InterfaceVersionHelperBase<Interface_t, Interface_v1_t, 1, &Interface_v1_deserialize>
{};
template <>
struct InterfaceVersionHelper<Interface_t, 2> :InterfaceVersionHelperBase<Interface_t, Interface_v2_t, 2, &Interface_v2_deserialize>
{};
template <>
struct InterfaceVersionHelper<Interface_t, 3> :InterfaceVersionHelperBase<Interface_t, Interface_v3_t, 3, &Interface_v3_deserialize>
{};
static bool r1 = []() {
InterfaceVersionHelper<Interface_t, 1>::registerMe();
InterfaceVersionHelper<Interface_t, 2>::registerMe();
InterfaceVersionHelper<Interface_t, 3>::registerMe();
return true;
}();
template <>
struct LatestInterface<Interface_t> :public Interface_LatestVersion<Interface_t, 3> {};
static bool r =
InterfaceRegistererDefintion<
Interface_t,
InterfaceV<Interface_v3_t, 3, &Interface_v3_deserialize>,
InterfaceV<Interface_v2_t, 2, &Interface_v2_deserialize>,
InterfaceV<Interface_v1_t, 1, &Interface_v1_deserialize>
>::create();
#include <list>
#include <map>
#include <iostream>
#include <sstream>
#include <memory>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <functional>
template <typename T>
using DeserFun = void(std::stringstream&, T*);
template<typename IFACE>
void DummyDeser(std::stringstream& io_str, IFACE* o_d) {};
template <typename T>
struct InterfaceVersionHelperBaseBase {
using value_type_target = T;
virtual int version()const = 0;
virtual void deserialize(std::stringstream& io_str, T* o_d) = 0;
};
template <typename T, int LatestVersion>
struct Interface_LatestVersion {
enum {
version = LatestVersion
};
using value_type = T;
};
template <typename T>
struct LatestInterface :public Interface_LatestVersion<T, 0> {};
template <typename T>
struct Interface_Deserializer {
using value_type = T;
std::map<int, std::shared_ptr<InterfaceVersionHelperBaseBase<T>>> versionMap;
static Interface_Deserializer& instance() {
static Interface_Deserializer s_instance;
return s_instance;
};
void deserialize(std::stringstream& io_str, T* o_d)const {
int v = 0;
io_str >> v;
auto it = versionMap.find(v);
if (it != versionMap.end()) {
(*it).second->deserialize(io_str, o_d);
} else {
std::cerr << "unknown version " << v << " for " << typeid(T).name() << std::endl;
}
}
private:
Interface_Deserializer() {};
};
template <typename T, typename IFACE, int IFACE_VER, DeserFun<IFACE> DESER_FUN>
struct InterfaceVersionHelperBase : public InterfaceVersionHelperBaseBase<T>
{
using value_type_current = IFACE;
enum { ver = IFACE_VER };
int version()const override { return IFACE_VER; };
/// deserializes stream and converts to latest type
void deserialize(std::stringstream& io_str, T* o_d) override {
value_type_current o;
DESER_FUN(io_str, &o);
Converter<T, IFACE_VER, LatestInterface<T>::version>::convert(&o, o_d);
return;
};
/// registers helper for this interface version on the Interface_Deserializer
static void registerMe() {
std::pair<int, std::shared_ptr<InterfaceVersionHelperBaseBase<T>>> v;
v.first = IFACE_VER;
v.second.reset(new InterfaceVersionHelperBase<T, IFACE, IFACE_VER, DESER_FUN>());
Interface_Deserializer<T>::instance().versionMap.insert( v );
}
};
/// this has to be specialized for each interface version to point to the correct types and deserializer
template <typename IFACE, int IFACE_VER>
struct InterfaceVersionHelper :public InterfaceVersionHelperBase < IFACE, IFACE, 0, &DummyDeser<IFACE> >
{
};
/// generic converter that converts between two interface versions by converting the input one version up
/// by calling user convert function
/// this can also be specialized by used to implement specific from x to latest converter
template <typename IFACE, int IFACE_VER, int IFACE_VER2>
struct Converter {
static void convert(const typename InterfaceVersionHelper < IFACE, IFACE_VER>::value_type_current* i_d,
typename InterfaceVersionHelper < IFACE, IFACE_VER2>::value_type_current* o_d)
{
InterfaceVersionHelper < IFACE, IFACE_VER + 1>::value_type_current temp;
::convert(i_d, &temp);
Converter<IFACE, IFACE_VER + 1, IFACE_VER2>::convert(&temp, o_d);
}
};
/// converter specialization that aborts conversion, if both sides are the same interface versions
template <typename IFACE, int IFACE_VER>
struct Converter<IFACE, IFACE_VER, IFACE_VER>{
static void convert(const typename InterfaceVersionHelper < IFACE, IFACE_VER>::value_type_current* i_d,
typename InterfaceVersionHelper < IFACE, IFACE_VER>::value_type_current* o_d)
{
*o_d = *i_d;
}
};
/////////////////////////////
// user types / deserializers
/////////////////////////////
typedef struct sInterface_v1_t {
int i;
}Interface_v1_t;
typedef struct sInterface_v2_t {
int i;
int j;
}Interface_v2_t;
typedef struct sInterface_v3_t {
int j;
float u;
}Interface_v3_t;
// latest version
typedef Interface_v3_t Interface_t;
void Interface_v1_deserialize(std::stringstream& io_str, Interface_v1_t* o_d)
{
io_str >> o_d->i;
}
void Interface_v2_deserialize(std::stringstream& io_str, Interface_v2_t* o_d)
{
io_str >> o_d->i;
io_str >> o_d->j;
}
void Interface_v3_deserialize(std::stringstream& io_str, Interface_v3_t* o_d)
{
io_str >> o_d->j;
io_str >> o_d->u;
}
/////////////////////////////
// user converter
/////////////////////////////
static void convert(const Interface_v1_t* i_d, Interface_v2_t* o_d) {
o_d->i = i_d->i;
o_d->j = 0;
}
static void convert(const Interface_v2_t* i_d, Interface_v3_t* o_d) {
o_d->j = i_d->j;
o_d->u = 0.f;
}
// specialization for specific conversion
template <>
struct Converter<Interface_t, 1, 3> {
static void convert(const Interface_v1_t* i_d,
Interface_v3_t* o_d)
{
o_d->u = float(i_d->i);
o_d->j = 0;
}
};
/////////////////////////////
// user boiler plate
/////////////////////////////
template <>
struct InterfaceVersionHelper<Interface_t, 1> :InterfaceVersionHelperBase<Interface_t, Interface_v1_t, 1, &Interface_v1_deserialize>
{};
template <>
struct InterfaceVersionHelper<Interface_t, 2> :InterfaceVersionHelperBase<Interface_t, Interface_v2_t, 2, &Interface_v2_deserialize>
{};
template <>
struct InterfaceVersionHelper<Interface_t, 3> :InterfaceVersionHelperBase<Interface_t, Interface_v3_t, 3, &Interface_v3_deserialize>
{};
static bool r1 = []() {
InterfaceVersionHelper<Interface_t, 1>::registerMe();
InterfaceVersionHelper<Interface_t, 2>::registerMe();
InterfaceVersionHelper<Interface_t, 3>::registerMe();
return true;
}();
template <>
struct LatestInterface<Interface_t> :public Interface_LatestVersion<Interface_t, 3> {};
/*
// desired user boiler plate:
static bool r =
InterfaceRegistererDefintion<
Interface_t,
InterfaceV<Interface_v3_t, 3, &Interface_v3_deserialize>,
InterfaceV<Interface_v2_t, 2, &Interface_v2_deserialize>,
InterfaceV<Interface_v1_t, 1, &Interface_v1_deserialize>
>::create();
*/
/////////////////////////////
// user test data
/////////////////////////////
std::string data_1 = "I 1 5";
std::string data_2 = "I 2 7 2";
std::string data_3 = "I 3 1 3.54";
std::string data_4 = "I 4 1 3.54 3.14159";
int main(int argc, char* argv[])
{
std::string ts;
int ti;
{ // test deserializer
std::stringstream s1(data_1);
std::stringstream s2(data_2);
std::stringstream s3(data_3);
s1 >> ts >> ti; // remove type and version from string
s2 >> ts >> ti; //
s3 >> ts >> ti; //
Interface_v1_t i1 = { 0 };
Interface_v2_t i2 = { 0 };
Interface_v3_t i3 = { 0 };
Interface_v1_deserialize(s1, &i1);
Interface_v2_deserialize(s2, &i2);
Interface_v3_deserialize(s3, &i3);
}
{// test helper deserialziation and conversion
std::stringstream s1(data_1);
std::stringstream s2(data_2);
std::stringstream s3(data_3);
s1 >> ts >> ti; // remove type and version from string
s2 >> ts >> ti; //
s3 >> ts >> ti; //
Interface_t i1 = { 0 };
Interface_t i2 = { 0 };
Interface_t i3 = { 0 };
InterfaceVersionHelper< Interface_t, 1> h1;
InterfaceVersionHelper< Interface_t, 2> h2;
InterfaceVersionHelper< Interface_t, 3> h3;
h1.deserialize(s1, &i1);
h2.deserialize(s2, &i2);
h3.deserialize(s3, &i3);
}
{// test Interface_Deserializer
std::stringstream s1(data_1);
std::stringstream s2(data_2);
std::stringstream s3(data_3);
std::stringstream s4(data_4);
s1 >> ts; // remove type from string
s2 >> ts; //
s3 >> ts; //
s4 >> ts; //
Interface_t i1 = { 0 };
Interface_t i2 = { 0 };
Interface_t i3 = { 0 };
Interface_t i4 = { 0 };
auto ds = Interface_Deserializer<Interface_t>::instance();
ds.deserialize(s1, &i1);
ds.deserialize(s2, &i2);
ds.deserialize(s3, &i3);
ds.deserialize(s4, &i4); // should output an error
}
return 0;
}