سؤال

وأريد أن تتخصص جزئيا قالب موجود أنني لا أستطيع تغيير (std::tr1::hash) لفئة أساسية وجميع الفئات المشتقة منها. والسبب هو أن أنا باستخدام نمط القالب الغريب متكرر لتعدد الأشكال، ويتم تنفيذ دالة تجزئة في الفئة الأساسية CRTP. إذا كنت تريد فقط للتخصص جزئيا لفئة أساسية CRTP، ثم أنه من السهل، أستطيع أن أكتب فقط:


namespace std { namespace tr1 {

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

} }

ولكن هذا التخصص لا يتطابق مع الفئات المشتقة الفعلية، CRTPBase<Derived> فقط. ما أريده هو وسيلة لكتابة التخصص الجزئي للDerived إذا وفقط إذا كان يستمد من CRTPBase<Derived>. بلدي شبه متاحة


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

} }

و... ولكن هذا لا يعمل لأن المترجم لا يمكن أن أقول أن enable_if<condition, Derived>::type هو Derived. إذا كان بإمكاني تغيير std::tr1::hash، كنت فقط إضافة معلمة قالب وهمية أخرى لاستخدام boost::enable_if، على النحو الموصى به من قبل وثائق enable_if، ولكن هذا ليس حلا جيدا للغاية. هل هناك طريقة للتغلب على هذه المشكلة؟ هل يجب أن تحديد قالب التجزئة المخصصة على كل unordered_set أو unordered_map I خلق، أو كليا متخصصون hash لكل فئة مشتقة؟

هل كانت مفيدة؟

المحلول

وهناك نوعان من المتغيرات في التعليمات البرمجية التالية. هل يمكن أن تختار أكثر خصصت لك.


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

}

نصائح أخرى

وبدلا من تعديل std::tr1::hash يجب عليك ان تجعل مساحة الاسم الخاص بك وتحديد هناك جديد hash هيكل التي ورثت من std::tr1::hash أو متخصصة ل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

}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top