2009-05-06 172 views
3

因此,我一直遇到的一个问题模式并没有很好的解决方案,那就是如何提供基于模板参数派生自哪种类型的模板专业化。 例如,假设我有:模式可以基于继承来专门化模板吗?

template<typename T> 
struct implementPersist; 

template<typename T> 
void persist(T& object) 
{ 
    implementPersist::doPersist(object); 
} 

我想是的用户坚持要能够提供implementPersist的实现::持续类型是上述后声明。原则上这很简单,但在实践中很麻烦,但用户需要为每种类型提供一个implement实用程序。

更清晰,假设我有:

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... } }; 

我的本意是,我提供一个模板实施的所有子类坚持,另一个用于myBoostPersistedObject的所有子类和杂项类不有趣的类结构(例如各种POD类型)。 然而,在实践中,

implementPersist<Persistent>::doPersist 

如果::坚持只会被调用(T &)被称为T是正是一个持续对象。它回落到T = myClass的(缺失)泛型情况。一般来说,我希望能够以基于继承的通用方式专门化模板。由于清楚的编译器知道如何做到这一点,并且在决定根据参数调用函数时做到这一点,所以它有点令人沮丧。

void persist(Persistent &); void persist(X &); void persist(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(); } } 
}; 

(见here为isDerivedFrom)。

但是,这要求implementsPersist的初始声明知道提供实现的类的类型。我想要更通用的东西。

我经常为这种模式找到用途,以避免为我的系统中的每个类添加明确的特化。

任何想法?

+0

我无法解释为什么你的编译器不会做你想要的类型推断。但是,我的经验与您的经验是一致的,因为模板和继承看起来不是很好。 – 2009-05-06 05:39:28

回答

3

是的,你可以做到这一点使用enable_if。

#include <iostream> 
#include <boost/type_traits.hpp> 
using namespace std; 


template <bool Enable, typename T = void> 
struct enable_if 
{ 
    typedef T type; 
}; 

template <typename T> 
struct enable_if<false, T> 
{ 
}; 

template <typename T, typename Enable = void> 
struct persist_t {}; 

struct A 
{ 
    virtual void foo() const = 0; 
}; 

template <typename T> 
struct persist_t<T, typename enable_if<boost::is_base_of<A, T>::value>::type> 
{ 
    static void persist(T const& x) 
    { 
     x.foo(); 
    } 
}; 


struct B : A 
{ 
    virtual void foo() const { cout << "B::foo\n"; } 
}; 

template <typename T> 
void persist(T & x) 
{ 
    persist_t<T>::persist(x); 
} 

int main() 
{ 
    B b; 
    persist(b); 
} 

Boost有一个更好的实现enable_if,我只是在这里提供它的完整性。 Boost也有一个使用它的例子,它与我上面的例子非常相似。

希望有所帮助。

+0

使用enable_if看起来不正确。您通常将其作为返回类型(或作为构造函数中的冗余默认参数)。你有链接到类似的提升示例? – 2009-05-06 10:09:07

0

尝试使用基本类型的引用来引用派生类型:

MyClass x(...); 
Persistent * p = &x; 
implementPersist<Persistent> ip; 
ip.doPersist(*p);