2

我有一个类Foo,它使用 CRTP 从父类继承模板方法,避免必须提供几十个单独的成员方法。像这样的东西:

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_类型(其中一种在Foo构造函数中通过配置文件中给出的名称进行实例化),只要它们遵守提供bool shouldDoStuff方法的公共接口即可。问题在于,这导致我定义以下内容:

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

对于所有FoxMods要实现的东西(比如,class redMountainLogic : public IFoxMod可能有它自己的辨别方式,当它适合做事情时)。

这是非法的,因为一个人不能有虚拟模板,我正试图找到一种解决方法。基本上,我需要动态调度,但我传递的参数是一个模板。我想不出解决方法。

4

1 回答 1

1

虚函数表似乎与模板特化不太协调。不会太令人惊讶。VFT 通常基于声明顺序,而模板并不真正存在。一种解决方案是手动重新创建 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 回答