我有一个类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;
}