【发布时间】:2009-05-06 04:49:28
【问题描述】:
所以,我经常遇到的一个问题模式是,如何提供基于模板参数派生的类型的模板特化。 例如,假设我有:
template<typename T>
struct implementPersist;
template<typename T>
void persist( T& object )
{
implementPersist::doPersist( object );
}
我希望persist 的用户能够为在上述之后声明的类型提供implementPersist::persist 的实现。这在原则上很简单,但在实践中很麻烦,但用户需要为每种类型提供一个 implementPersist。
为了更清楚,假设我有:
struct Persistent { virtual void myPersist() = 0; };
struct MyClass : public persistent { virtual void MyPersist() { ...implementation...} };
// Persists subclasses of Persistent using myPersist
template<>
struct implementPersist<Persistent>{ void doPersist(Persistent& p) { p->myPersist(); } };
struct X{};
template<>
struct implementPersist<X>{ void doPersist(X& p) { ...implementation...} };
// Persists subclasses of Persistent using boostPersist
struct MyBoostPersistedObject { virtual void boostPersist() = 0 };
struct Z : public MyBoostPersistedObject { virtual void boostPersist() = 0 };
template<>
struct implementPersist<myBoostPersistedObject>{ void boostPersist() { ...implementation... } };
我的意图是为 Persist 的所有子类提供一个模板实现,为 myBoostPersistedObject 的所有子类提供另一个模板实现,以及为不在有趣的类结构中的杂类(例如各种 POD 类型)提供另一个模板实现。 然而,在实践中,
implementPersist<Persistent>::doPersist
只有在调用 ::persist(T&) 时才会被调用,其中 T 恰好是一个 Persistent 对象。它回退到 T=myClass 的(缺失的)通用情况。一般来说,我希望能够以基于继承的通用方式专门化模板。这有点令人沮丧,因为显然编译器知道如何做到这一点,并且在决定基于参数调用函数时这样做,例如
void 持久化(持久化&); 无效坚持(X&); 无效持久(myBoostPersistedObject&);
但据我所知,模板无法进行类似的匹配。
一种解决方法是:
class persist;
template<typename T, bool hasMyPersistMethod=isDerivedFrom(T,persist)::value >
struct implementPersist;
template<typename T, bool true >
struct implementPersist<T,true>
{
template<> struct implementPersist<X>{ void doPersist(T& p) { p->myPersist(); } }
};
(有关 isDerivedFrom,请参见 here)。
但是,这要求implementPersist 的初始声明知道提供实现的类的类型。我想要更通用的东西。
我经常发现这种模式的用途,以避免为我的系统中的每个类添加明确的专业化。
有什么想法吗?
【问题讨论】:
-
我无法解释为什么您的编译器不会进行您想要的类型推断。但是,我的经验与你的一致,模板和继承似乎不能很好地结合在一起。