2009-06-23 28 views
6

Tôi muốn một phần chuyên về mẫu hiện có mà tôi không thể thay đổi (std::tr1::hash) cho một lớp cơ sở và tất cả các lớp có nguồn gốc. Lý do là tôi đang sử dụng mẫu khuôn mẫu tò mò định kỳ cho đa hình, và hàm băm được thực hiện trong lớp cơ sở CRTP. Nếu tôi chỉ muốn một phần chuyên cho một lớp cơ sở CRTP, sau đó thật dễ dàng, tôi chỉ có thể viết:Làm thế nào để một phần chuyên về một mẫu lớp cho tất cả các loại có nguồn gốc?


namespace std { namespace tr1 { 

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

} } 

Nhưng chuyên môn hóa này không phù hợp với các lớp thừa kế thực tế, chỉ CRTPBase<Derived>. Điều tôi muốn là cách viết chuyên môn từng phần cho Derived nếu và chỉ khi nó xuất phát từ CRTPBase<Derived>. pseudo-code của tôi là


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

} } 

... nhưng điều đó không làm việc vì trình biên dịch không thể nói rằng enable_if<condition, Derived>::typeDerived. Nếu tôi có thể thay đổi std::tr1::hash, tôi chỉ cần thêm một thông số mẫu giả khác để sử dụng boost::enable_if, theo khuyến cáo của tài liệu enable_if, nhưng đó rõ ràng không phải là giải pháp tốt. Có cách nào xung quanh vấn đề này? Tôi có phải chỉ định mẫu băm tùy chỉnh trên mọi unordered_set hoặc unordered_map Tôi tạo hoặc hoàn toàn chuyên biệt hash cho mọi lớp dẫn xuất không?

Trả lời

7

Có hai biến thể trong đoạn mã sau. Bạn có thể chọn phù hợp hơn cho bạn.


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

Có vẻ tốt, cảm ơn. – Doug

1

Thay vì sửa đổi std::tr1::hash bạn nên tạo không gian tên của riêng mình và xác định cấu trúc mới hash được kế thừa từ std::tr1::hash hoặc dành riêng cho CRTPBase<Derived>.


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

Nhưng sau đó anh ấy vẫn phải chỉ định mẫu băm tùy chỉnh trên mọi unordered_set, vì nó sẽ không sử dụng không gian tên của anh ấy. –

Các vấn đề liên quan