2009-05-06 10 views
3

私が克服し続ける1つの問題のパターンは、テンプレートパラメータがどのタイプのものであるかに基づいてテンプレートの特殊化を提供する方法です。 は例えば、私が持っているとします継承に基づいてテンプレートを特殊化するパターンは可能ですか?

template<typename T> 
struct implementPersist; 

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

私が好きなどんなことimplementPersistの実装を提供することができるように存続のユーザー向けです::上記の後に宣言されているタイプのために存続します。原則的には簡単ですが、実際には扱いにくいですが、ユーザーはすべての型に対して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... } }; 

私の意図は、私はmyBoostPersistedObjectのすべてのサブクラスのため、別のものを持続し、他のではない雑多なクラスのためにのすべてのサブクラスのための1つのテンプレートの実装を提供することをあります興味深いクラス構造(例えば、様々なPODタイプ)。 Tは、正確永続オブジェクトであるが実際には 、::が続く場合

implementPersist<Persistent>::doPersist 

にしか起動され(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(); } } 
}; 

(isDerivedFromためhereを参照してください):

回避策の一つのような何かを行うことです。

しかし、これはimplementPersistの初期宣言が実装を提供するクラスの型を知ることを必要とします。私はより一般的な何かが欲しいです。

システムのすべてのクラスに明示的な特殊化を追加しないように、このようなパターンの使用が頻繁にあります。

アイデア?

+0

私はあなたのコンパイラがあなたが望む型推論をしない理由を説明できません。しかし、私の経験は、テンプレートと継承が一緒にうまくいっていないという意味で、あなたのものと一貫しています。 –

答えて

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

ブーストはenable_ifのよりよい実装を持って、私は完全を期すため、ここでそれを提供しました。ブーストには、私の上記の例と非常によく似た使い方の例もあります。

希望に役立ちます。

+0

enable_ifを使用しても正しく表示されません。あなたは通常、戻り値の型として(またはコンストラクタの冗長なデフォルトのパラメータとして)持っています。あなたは同様のブーストの例へのリンクを持っていますか? –

+0

はい、上記のenable_ifをクリックしてください。ここにはとにかく:http://www.boost.org/doc/libs/1%5F39%5F0/libs/utility/enable%5Fif.html – Yuyo

+0

ありがとう - 私はその使用法について知らなかった –

0

は派生型を参照するために、ベース型の参照を使用してみてください:

MyClass x(...); 
Persistent * p = &x; 
implementPersist<Persistent> ip; 
ip.doPersist(*p); 
関連する問題