Frage

Ich mag teilweise eine bestehende Vorlage spezialisiert, die ich nicht (std::tr1::hash) für eine Basisklasse und alle abgeleiteten Klassen ändern. Der Grund dafür ist, dass ich das merkwürdig einmalige Vorlage Muster für Polymorphismus bin mit, und der Hash-Funktion ist in der CRTP Basisklasse implementiert. Wenn ich nur zum Teil will für eine der CRTP Basisklasse spezialisiert hat, dann ist es einfach, ich kann nur schreiben:


namespace std { namespace tr1 {

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

} }

Aber diese Spezialisierung nicht tatsächlich abgeleiteten Klassen entsprechen, nur CRTPBase<Derived>. Was ich will, ist eine Möglichkeit, eine Teil-Spezialisierung für Derived des Schreibens, wenn und nur wenn sie von CRTPBase<Derived> ableitet. Mein Pseudo-Code ist


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

} }

... aber das funktioniert nicht, da der Compiler nicht, dass enable_if<condition, Derived>::type ist Derived sagen kann. Wenn ich std::tr1::hash ändern könnte, würde ich hinzufügen, nur ein weiterer Dummy-Template-Parameter boost::enable_if zu verwenden, wie sie in der enable_if Dokumentation empfohlen, aber das ist offensichtlich nicht eine sehr gute Lösung. Gibt es eine Möglichkeit, um dieses Problem? Muss ich eine eigene Hash-Vorlage auf jedem unordered_set angeben oder unordered_map ich erstellen oder vollständig hash für jede abgeleitete Klasse spezialisieren?

War es hilfreich?

Lösung

Es gibt zwei Varianten in dem folgenden Code. Sie könnten mehr für Sie eignen wählen.


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

}

Andere Tipps

Statt std::tr1::hash modifizieren sollten Sie Ihren eigenen Namensraum machen und dort neue Struktur hash definieren, die von std::tr1::hash geerbt oder für CRTPBase<Derived> spezialisiert.


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

}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top