如何在c++中将模板成员函数的实参转发给成员基类指针



我有一个类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可能有自己的识别方式,什么时候做事情是合适的)。

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

虚函数表似乎与模板特化不能很好地相处。这并不奇怪。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;
}

最新更新