2009-06-23 32 views
6

Temel sınıf ve türetilmiş sınıflar için değiştiremediğim (std::tr1::hash) mevcut bir şablonu kısmen uzmanlaştırmak istiyorum. Nedeni, polimorfizm için merakla tekrar eden şablon desenini kullanıyorum ve karma işlevi CRTP taban sınıfında uygulanmış olmasıdır.Türetilmiş türler için bir sınıf şablonunun kısmen nasıl uzmanlaştırılır?


namespace std { namespace tr1 { 

template <typename Derived> 
struct hash<CRTPBase<Derived> > 
{ 
    size_t operator()(const CRTPBase<Derived> & base) const 
    { 
     return base.hash(); 
    } 
}; 

} } 

Ama bu uzmanlık gerçek türetilmiş sınıfları, sadece CRTPBase<Derived> eşleşmiyor: Ben sadece kısmen bir CRTP temel sınıf için uzmanlaşmak istiyorsanız, o zaman ben sadece yazabilir, kolay. İstediğim şey, yalnızca CRTPBase<Derived>'dan kaynaklanıyorsa Derived için kısmi bir uzmanlık yazmanın bir yoludur. Benim sözde kod


namespace std { namespace tr1 { 

template <typename Derived> 
struct hash<typename boost::enable_if<std::tr1::is_base_of<CRTPBase<Derived>, Derived>, 
    Derived>::type> 
{ 
    size_t operator()(const CRTPBase<Derived> & base) const 
    { 
     return base.hash(); 
    } 
}; 

} } 

... ama derleyici enable_if<condition, Derived>::type Derived olduğunu söyleyemem çünkü çalışmıyor. std::tr1::hash'u değiştirebilirsem, enable_if belgelerinin önerdiği gibi boost::enable_if kullanmak için başka bir kukla şablon parametresi ekleyebilirim, ancak bu kesinlikle çok iyi bir çözüm değildir. Bu problemin bir yolu var mı? Oluşturduğum her unordered_set veya unordered_map her özel hash şablonunu belirtmeli mi yoksa her türetilmiş sınıf için hash tamamen uzmanlaşmalı mıyım? Bunun yerine kendi ad yapmak ve std::tr1::hash miras veya CRTPBase<Derived> için uzmanlaşmıştır orada yeni bir yapı hash tanımlamalıdır std::tr1::hash değiştirme

cevap

7

Aşağıdaki kodda iki varyant vardır. Sizin için daha uygun olanı seçebilirsiniz.


template <typename Derived> 
struct CRTPBase 
{ 
    size_t hash() const {return 0; } 
}; 

// First case 
// 
// Help classes 
struct DummyF1 {}; 
struct DummyF2 {}; 
struct DummyF3 {}; 
template<typename T> struct X; 

// Main classes 
template<> struct X<DummyF1> : CRTPBase< X<DummyF1> > { 
    int a1; 
}; 

template<> struct X<DummyF2> : CRTPBase< X<DummyF2> > { 
    int b1; 
}; 

// typedefs 
typedef X<DummyF1> F1; 
typedef X<DummyF2> F2; 
typedef DummyF3 F3; // Does not work 

namespace std { namespace tr1 { 
    template<class T> 
    struct hash< X<T> > { 
     size_t operator()(const CRTPBase< X<T> > & base) const  
     {   
      return base.hash();  
     } 
    }; 
}} // namespace tr1 // namespace std 

// 

// Second case 
struct DummyS1 : CRTPBase <DummyS1> { 
    int m1; 
}; 
// 
template<typename T> 
struct Y : T {}; 
// 
typedef Y<DummyS1> S1; 


namespace std { namespace tr1 { 
    template<class T> 
    struct hash< Y<T> > { 
     size_t operator()(const CRTPBase<T> & base) const  
     {   
      return base.hash();  
     } 
    }; 
}} // namespace tr1 // namespace std 

void main1() 
{ 
    using std::tr1::hash; 
    F1 f1; 
    F2 f2; 
    F3 f3; 
    hash<F1> hf1; size_t v1 = hf1(f1); // custom hash functor 
    hash<F2> hf2; size_t v2 = hf2(f2); // custom hash functor 
    hash<F3> hf3; size_t v3 = hf3(f3); // error: standard hash functor 

    S1 s1; 
    hash<S1> hs1; size_t w1 = hs1(s1); // custom hash functor 

} 
+0

İyi görünüyor, teşekkürler. – Doug

1

.


template <typename Derived> 
struct CRTPBase 
{ 
    size_t hash() {return 0; } 
}; 

struct AA : CRTPBase <AA> {}; 
struct BB {}; 
// 
namespace mynamespace { 

template <typename Some, typename Dummy=char> 
struct hash : std::tr1::hash<Some> {}; 
// 
template <typename Derived> 
struct hash<Derived, 
    typename boost::enable_if< std::tr1::is_base_of<CRTPBase<Derived>, Derived>, char>::type > 
{  
    size_t operator()(const CRTPBase<Derived> & base) const  
    {   
     return base.hash();  
    } 
}; 

} // namespace mynamespace {} 
// 
// 
void ff() 
{ 
    using namespace mynamespace; 

    hash<AA> aa; // my hash 
    hash<BB> bb; // std::tr1::hash 

} 
+1

Ancak, daha sonra, her unordered_set öğesinde, ad alanını kullanmayacağı için özel bir karma şablonu belirtmesi gerekir. –

İlgili konular