私が行っているプライベートプロジェクトでシリアライズしたいタイプの基本クラスとして機能するクラスを構築しようとしています。
「<<」と「>>」の機能を提供することで、少なくともシリアル化アーカイブと 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++ におけるオブジェクト指向プログラミングとジェネリック プログラミングの間の緊張と、それについて型消去ができること(「Beyond 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 の間)。
私はまだ Type Erasure が答えだと思っています。使い方がわかりません。
そう、
- 私が望む動作を達成することは可能ですか? もし、そうなら:
- 仮想テンプレートが違法な場合に、この「マルチレベル NVI」動作を許可するクラスを実現するにはどうすればよいですか?
編集:これは解決策になる と思いますが、まだ適切にテストできません。