2009-05-06 144 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);