2

FooCRTP を使用して親クラスからテンプレート メソッドを継承するクラスがあり、文字通り数十の個別のメンバー メソッドを提供する必要がありません。このようなもの:

class Foo : public SomeBarClass<Foo>
{
//..
//from SomeBarClass
public:
    template <class T> void onMsg(T* msg);

private:
    IFoxMod* foxMod_;
};

の実装ではonMsg、次のようなものが必要です。

template <class T>
void Foo::onMsg(T* msg)
{
    if (foxMod_->shouldDoStuff(msg))
    {
        //do stuff
    }
}

また、メソッドを提供する共通のインターフェースに準拠している限り、多くのタイプが存在する可能性がありfoxMod_ます (構成ファイルで指定された名前でコンストラクターでインスタンス化されたもののうちの 1 つ) 。問題は、これが次の定義につながることです。Foobool shouldDoStuff

struct IFoxMod
{
    virtual ~IFoxMod() {}
    template <class T> shouldDoStuff(T* msg) = 0;
};

FoxMods実装するすべてのclass redMountainLogic : public IFoxMod場合(たとえば、物事を行うのが適切な場合は、独自の識別方法がある場合があります)。

ただし、仮想テンプレートを使用できないため、これは違法であり、回避策を見つけようとしています。基本的に動的ディスパッチが必要ですが、渡す引数はテンプレートです。回避策が思いつきません。

4

1 に答える 1

1

仮想関数テーブルは、テンプレートの特殊化とうまく調和していないようです。それほど驚くべきことではありません。VFT は通常、宣言の順序に基づいていますが、これはテンプレートには実際には存在しません。1 つの解決策は、VFT を手動で再作成することです。

これが例です。おそらく少しきれいになるかもしれませんが、うまくいきます。

#include<iostream>
using namespace std;

// Message.h

template<int n>
struct MessageByInt {
  typedef int Msg;
};

struct MessageOfHope {
  int a;
  int b;
  static const int id = 0;
};
template<> struct MessageByInt<MessageOfHope::id> { typedef MessageOfHope Msg; };

struct MessageOfDoom {
  int b;
  int c;
  static const int id = 1;
};
template<> struct MessageByInt<MessageOfDoom::id> { typedef MessageOfDoom Msg; };

const int nMessages = 2;

// IFoxMod.h

typedef bool(*callback)(void*);

struct IFoxMod {
  callback vtable[nMessages];
  template<typename MSG>
  bool ShouldDoWork(MSG* msg) {
    return vtable[MSG::id](msg);
  }
};

template<typename TESTER, int n>
struct filler {
  typedef typename MessageByInt<n>::Msg MSG;
  typedef typename TESTER::template Tester<MSG> Tester;
  static void fill(IFoxMod* impl) {
    impl->vtable[n] = reinterpret_cast<callback>(&Tester::ReallyShouldDoWork);
    filler<TESTER,n-1>::fill(impl);
  }
};

template<typename TESTER>
struct filler<TESTER,-1>{
  static void fill(IFoxMod* impl) {
  }
};

// RedFox.h

struct RedFoxTester {
  template<typename MSG>
  struct Tester { // This struct exists to allow partial specialization
    static bool ReallyShouldDoWork(MSG* msg) {
      return msg->b == 2;
    }
  };
};

struct RedFoxMod : public IFoxMod {
  RedFoxMod() {
    filler<RedFoxTester,nMessages-1>::fill(this);
  }
};

//Main

main() {
  IFoxMod* fm = new RedFoxMod();
  MessageOfHope mohb2 = {1, 2};
  MessageOfDoom modb2 = {2, 3};
  MessageOfHope mohbn2 = {2, 3};
  MessageOfDoom modbn2 = {1, 2};
  cout << fm->ShouldDoWork(&mohb2) << ", " << fm->ShouldDoWork(&modb2) << endl;
  cout << fm->ShouldDoWork(&mohbn2) << ", " << fm->ShouldDoWork(&modbn2) << endl;
}
于 2013-01-10T05:36:43.163 に答える