1

テンプレートメンバー関数のインターフェイスを定義する一般的な方法はありますか?派生クラスでオーバーライドする必要があるテンプレートメンバー関数の宣言を使用して、いくつかの純粋な抽象基本クラスを作成したいと思います。インターフェイスを介して派生クラスの関数を呼び出せるようにしたいよりも。仮想テンプレートメンバー関数が許可されていないことを知っています。だから今まで私は次の解決策を思いついた(下記参照)。私が知りたいのは、私のアプローチが悪いデザインなのか、それとも私の目標を達成するためのより良い方法があるのか​​ということです。

編集:私が実装したいのはシリアル化システムです(boost :: serializationに似ています)。そのため、オブジェクトの保存とロードに使用できる共通のベースインターフェイス関数をシリアル化してもらいたいと思います。保存とロードの正しい関数呼び出しは、* do_serialize *関数を呼び出すときに、提供された派生アーカイブクラスによって決定されます。

提供されたソリューションについてよくわからないので、目標を達成するためのより良い方法(またはさらに簡単な方法)があるかどうかを尋ねたいと思います。

インターフェイス:

template<typename Derived>
class Archive{
public:
  virtual ~Archive() = 0 {}

  template<typename T>
  Archive& serialize(T t) {
    Derived* derived = static_cast<Derived*>(this);
    return derived->serialize_derived(t);
  }
};

template<typename Derived>
class Writer : public Archive<Derived> {
public:
  virtual ~Writer() = 0 {}

  template<typename T> 
  void write(const T& t) {
    Derived* derived = static_cast<Derived*>(this);
    derived->write_derived(t);
  }
};

template<typename Derived>
class Reader : public Archive<Derived> {
public:
  virtual ~Reader() = 0 {}

  template<typename T> 
  void read(const T& t) {
    Derived* derived = static_cast<Derived*>(this);
    derived->read_derived(t);
  }
};

派生クラス:

class BinaryWriter : public Writer<BinaryWriter> {
public:
  template<typename T>
  BinaryWriter& serialize_derived(T t) {
    save(t);
    return *this;
  }

  template<typename T>
  void save(T t) {
    std::cout << "DerivedWriter::save: " << t << std::endl;
  }

  template<typename T> 
  void write_derived(const T& t) {
    std::cout << "DerivedWriter::write_derived: " << t << std::endl;
  }
};

class BinaryReader : public Reader<BinaryReader> {
public:
  template<typename T>
  BinaryReader& serialize_derived(T t) {
    load(t);
    return *this;
  }

  template<typename T>
  void load(T t) {
    std::cout << "DerivedWriter::load: " << t << std::endl;
  }

  template<typename T> 
  void read_derived(const T& t) {
    std::cout << "DerivedReader::read_derived: " << t << std::endl;
  }
};

テスト関数と呼び出しの例(注:ライター/リーダーインターフェイスへの呼び出しも同様に必要です(他の派生ライター/リーダークラスはここでは省略されています(つまり、TextReader、XMLReaderなど))):

template<typename Derived, typename T>
void do_serialize(Archive<Derived>& obj, T t) {
  obj.serialize(t);
}

DerivedWriter dw;
DerivedReader dr;

do_serialize(dw, 1);
do_serialize(dr, 2);

出力:

DerivedWriter::save: 1
DerivedReader::read: 2
4

1 に答える 1

2

この手法が CRTP と呼ばれていることを知った後 (pmr に感謝) 、仮想メンバー関数のオーバーヘッドを回避するためにこの投稿 CRTP を見つけました。これは私の質問に答えていると思います。その投稿の Kerrek SB の回答で述べたように、この手法を使用してインターフェイスを提供できます。私の場合、このインターフェイスはテンプレート メンバー関数に対しても定義できます。

このパターンは非常に一般的であるように思われるので (これについてはよくわかりませんでした)、私の質問に対する回答として受け入れます。

返信ありがとうございます。

于 2012-07-27T10:19:09.667 に答える