我正在尝试构建一个类,该类将充当我想要在我正在做的私人项目中序列化的任何类型的基类。
我试图通过为“<<”和“>>”提供功能来使该类至少与提升序列化档案和 QDataStream 一起工作。任何其他适用于该课程的流只是一个奖励。
重要提示:我可能只会使用 QDataStream。我将这门课更多地作为一个拼图/学习机会(这似乎有效),所以虽然我会欣赏完全偏离这种形式的解决方法,但如果事情能按照我希望的方式工作,我会非常喜欢(当然,考虑到语言的限制,尽可能接近),在途中获得一些知识。
我认为的课程是:
#ifndef SERIALIZABLE_H
#define SERIALIZABLE_H
#include <QObject>
#include <QDataStream>
#include <boost/serialization/access.hpp>
#include <boost/serialization/version.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/split_member.hpp>
// #include boost stl containers handlers...
class Serializable : public QObject
{
Q_OBJECT
template <typename Archive>
virtual void Serializable_save( Archive &out, const quint32 p_version = 0 ) = 0;
template <typename Archive>
virtual void Serializable_load( Archive &in, const quint32 p_version = 0 ) = 0;
quint32 m_ID;
quint16 m_version;
public:
explicit Serializable( QObject *parent = 0 ) : QObject( parent ) {}
BOOST_SERIALIZATION_SPLIT_MEMBER()
template <typename Archive>
void save( Archive &out, const quint32 p_version = 0 )
{
out << m_ID << m_version;
Serializable_save( out, p_version );
}
template <typename Archive>
void load( Archive &in, const quint32 p_version = 0 )
{
in >> m_ID >> m_version;
Serializable_load( in, p_version );
}
quint32 ID() const;
void setID( const quint32 &ID );
quint16 version() const;
void setVersion( const quint16 &version );
};
template <typename Archive>
Archive &operator << ( Archive &out, const Serializable &module )
{
module.save( out );
return out;
}
template <typename Archive>
Archive &operator >> ( Archive &in, Serializable &module )
{
module.load( in );
return in;
}
#endif // SERIALIZABLE_H
我立即发现不允许使用虚拟模板,并且遇到了(对我而言)新术语“类型擦除”。
阅读这篇文章后,我尝试使用类型擦除:论 C++ 中面向对象和泛型编程之间的张力以及类型擦除可以做什么(直到并包括“超越 boost::any”)...
不成功。
几点注意事项:
Serializable_save 和 Serializable_load 是命名约定的一部分,它遵循继承并允许多级 NVI。 (多级 NVI 只是我为完成从基类继承的虚函数并为继承者提供新虚函数的概念而起的一个名称。允许一组动作始终沿着继承链发生)意味着不是最终类的继承类将如下所示:
#ifndef DATAMODULE_I_H
#define DATAMODULE_I_H
#include <StorageGateway/serializable.h>
class DataModule_I : public Serializable
{
template <typename Archive>
virtual void DataModule_I_save( Archive &out ) = 0;
template <typename Archive>
virtual void DataModule_I_load( Archive &in ) = 0;
template <typename Archive>
virtual void Serializable_save( Archive &out ) final
{
// Some preconditions.
DataModule_I_save( out );
// Some postconditions.
}
template <typename Archive>
virtual void Serializable_load( Archive &in ) final
{
// Some preconditions.
DataModule_I_load( in );
// Some postconditions.
}
public:
explicit DataModule_I( const quint32 ID, QObject *parent = 0 );
};
#endif // DATAMODULE_I_H
我的下一个尝试是将“存档”模板埋在 StreamWrapper 类中(类似于类型擦除,但不完全是),以消除对模板的直接需求并通过编译器关于虚拟模板的无限问题。
当然,那没有用。因为我最终需要指定与我试图实现的完全相反的模板类型。
如果重要的话,我正在使用 C++14(我的意思是在 11 到 14 之间)。
我仍然认为类型擦除是答案。我只是不明白如何使用它。
所以,
- 是否有可能实现我想要的行为?如果是:
- 当虚拟模板非法时,如何实现允许这种“多级 NVI”行为的类?
编辑: 我认为这可能是一个解决方案,但我还不能正确测试它。