كيفية متخصصون جزئيا قالب فئة لجميع أنواع المستمدة؟
-
06-07-2019 - |
سؤال
وأريد أن تتخصص جزئيا قالب موجود أنني لا أستطيع تغيير (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
}