【发布时间】:2015-10-25 06:27:10
【问题描述】:
我正在为 stl 容器的反序列化编写模板类。
假设我想序列化一个set<int>。我有一个基本的serialisation 类和以下模板:
template<typename T>class serialiser;
template<>class serialiser<int>:public serialisation<int>{
public:
void serialise ( int t );
};
要序列化set,我有:
template<typename T>class Container_serialiser:public serialisation<T>{
public:
void serialise ( T t );
private:
/* Notice that I must declare a serialiser.
*/
serialiser<typename T :: value_type>value_serialiser;
};
template<typename T>void Container_serialiser<T>::serialise ( T t ){
for(typename T :: const_iterator t_iterator = t . begin ( );t_iterator != t . end ( );++ t_iterator){
value_serialiser . serialise ( * t_iterator );
}
}
这仅适用于其元素本身不包含容器的容器。
问题
如果我想序列化 map<int,set<int> > 怎么办?
由于每个元素的类型都是pair<int,set<int> >,我需要以下类:
template<>class serialiser<pair<int,set<int> > >:public serialisation<pair<int,set<int> > >{
public:
void serialise ( const pair<int,set<int> >t );
private:
serialiser<int>t_first_serialiser;
/* Notice that I must declare a Container_serialiser.
*/
Container_serialiser<set<int> >t_second_serialiser;
};
但是,Container_serialiser 要求 serialiser<T> 是完整类型。因此,直到上述类之后才能定义它。同样,上面的类要求Container_serialiser<T>是一个完整的类型,不能在它之前定义。
编译器给出以下错误:
prog.cpp: In instantiation of 'class Container_serialiser<std::map<int, std::set<int> > >':
prog.cpp:73:44: required from here
prog.cpp:40:39: error: 'Container_serialiser<T>::value_serialiser' has incomplete type
serialiser<typename T :: value_type>value_serialiser;
^
prog.cpp:25:27: note: declaration of 'class serialiser<std::pair<const int, std::set<int> > >'
template<typename T>class serialiser;
问题代码
#include <iostream>
#include <map>
#include <set>
#include <utility>
using std :: cout;
using std :: map;
using std :: set;
using std :: make_pair;
using std :: pair;
template<typename T>class serialisation{
public:
virtual ~serialisation ( );
protected:
virtual void serialise ( const T t ) = 0;
};
template<typename T>serialisation<T> :: ~serialisation ( ){
}
template<typename T>class serialiser;
template<>class serialiser<int>:public serialisation<int>{
public:
void serialise ( const int t );
};
void serialiser<int>:: serialise ( const int t ){
cout << t << '\n';
}
template<typename T>class Container_serialiser:public serialisation<T>{
public:
void serialise ( const T t );
private:
serialiser<typename T :: value_type>value_serialiser;
};
template<typename T>void Container_serialiser<T>:: serialise ( const T t ){
for(typename T :: const_iterator t_iterator = t . begin ( );t_iterator != t . end ( );++ t_iterator){
value_serialiser . serialise ( * t_iterator );
}
}
template<>class serialiser<pair<int,set<int> > >:public serialisation<pair<int,set<int> > >{
public:
void serialise ( const pair<int,set<int> >t );
private:
serialiser<int>t_first_serialiser;
Container_serialiser<set<int> >t_second_serialiser;
};
void serialiser<pair<int,set<int> > >:: serialise ( const pair<int,set<int> >t ){
t_first_serialiser . serialise ( t . first );
t_second_serialiser . serialise ( t . second );
}
int main ( ){
set<int>t;
t . insert ( 2 );
t . insert ( 3 );
Container_serialiser<set<int> >t_serialiser;
t_serialiser . serialise ( t );
map<int,set<int> >u;
u . insert ( make_pair ( 5,t ) );
u . insert ( make_pair ( 7,t ) );
Container_serialiser<map<int,set<int> > >u_serialiser;
u_serialiser . serialise ( u );
}
黑客攻击
我可以通过编写四个模板来完成这项工作:
-
serialiser0<T>用于所有不是容器且不包含容器的 T -
Container_serialiser0<T>代表所有 T,其value_type是serialiser0<T>的参数 -
serialiser1<T>用于所有不是容器但包含本身不包含容器的元素的容器的 T -
Container_serialiser1<T>代表所有 T,其value_type是serialiser1<T>的参数
这种设计是重复的、令人困惑的,并且必须为每个新级别的容器手动扩展。有更好的模式吗?
不幸的是,由于我正在从事的项目,我必须避免外部依赖,例如 boost.serialization,即使以牺牲性能为代价并为 C++98 标准编写。
破解代码
#include <iostream>
#include <map>
#include <set>
#include <utility>
using std :: cout;
using std :: map;
using std :: set;
using std :: make_pair;
using std :: pair;
template<typename T>class serialisation{
public:
virtual ~serialisation ( );
protected:
virtual void serialise ( const T t ) = 0;
};
template<typename T>serialisation<T> :: ~serialisation ( ){
}
template<typename T>class serialiser0;
template<>class serialiser0<int>:public serialisation<int>{
public:
void serialise ( const int t );
};
void serialiser0<int>:: serialise ( const int t ){
cout << t << '\n';
}
template<typename T>class Container_serialiser0:public serialisation<T>{
public:
void serialise ( const T t );
private:
serialiser0<typename T :: value_type>value_serialiser;
};
template<typename T>void Container_serialiser0<T>:: serialise ( const T t ){
for(typename T :: const_iterator t_iterator = t . begin ( );t_iterator != t . end ( );++ t_iterator){
value_serialiser . serialise ( * t_iterator );
}
}
template<typename T>class serialiser1;
template<>class serialiser1<pair<const int,set<int> > >:public serialisation<pair<int,set<int> > >{
public:
void serialise ( const pair<int,set<int> >t );
private:
serialiser0<int>t_first_serialiser;
Container_serialiser0<set<int> >t_second_serialiser;
};
void serialiser1<pair<const int,set<int> > >:: serialise ( const pair<int,set<int> >t ){
t_first_serialiser . serialise ( t . first );
t_second_serialiser . serialise ( t . second );
}
/* This is the same as Container_serialiser0!
*/
template<typename T>class Container_serialiser1:public serialisation<T>{
public:
void serialise ( const T t );
private:
serialiser1<typename T :: value_type>value_serialiser;
};
template<typename T>void Container_serialiser1<T>:: serialise ( const T t ){
for(typename T :: const_iterator t_iterator = t . begin ( );t_iterator != t . end ( );++ t_iterator){
value_serialiser . serialise ( * t_iterator );
}
}
int main ( ){
set<int>t;
t . insert ( 2 );
t . insert ( 3 );
Container_serialiser0<set<int> >t_serialiser;
t_serialiser . serialise ( t );
map<int,set<int> >u;
u . insert ( make_pair ( 5,t ) );
u . insert ( make_pair ( 7,t ) );
Container_serialiser1<map<int,set<int> > >u_serialiser;
u_serialiser . serialise ( u );
}
【问题讨论】:
-
你不能避免
Container_serialiser的定义,让所有的类都是serialiser的特化吗?并且对每种容器类型都有单独的专业化?在这种情况下,您可以定义serializer<int>、serializer< pair<T1, T2> >、serializer< set<T> >等。
标签: c++ templates serialization stl circular-dependency