Hashtable-Template



  • Hallo,

    ich möchte nen Template Hashtable<class type1, class type2> schreiben...
    Falls type1 von HashValue erbt, möchte ich die den Rückgabe-Wert dieser
    Methode nehmen, ansonsten möchte ich die anhand der Adresse einsortieren.

    Also etwa so:

    template<class type1, class type2>
    class Hashtable{
    public:
    	Hashtable();
    	virtual ~Hashtable();
    
    	virtual void put(type1, type2){
    		if (type1 instanceof HashValue)
    			// tue dies
    		else 
    			// tue das
    	}
    };
    

    #endif



  • Kann ich das irgendwie hinkriegen?

    Vielen Dank für eure Hilfe



  • sicher geht das AFAIK nicht. Du kannst zur kompilierzeit nur herausfinden _ob_ eine klasse erbt, nicht ob das public/protected/private ist. Du könntest auch prüfen ob die Klasse ne memberfunktion get_hash_value o.ä. hat (siehe adl), aber das ist auch unschön, weil _theoretisch_ get_hash_value auch was anderes sein könnte, als du erwartest.



  • iirc gilt diese Compilezeit-Ermittlung der Basisklasse nur für öffentliche Basisklassen (da nur dann die Umwandlung implizit funktioniert), ist also hier genau das richtige.

    // so siehts in "Modernes C++ Design" von Alexandrescu aus
    template <class T, class U>
    class Conversion
    {
        typedef char Small;
        class Big { char dummy[2] };
        static Small Test (U);
        static Big Test (...);
        static T MakeT ();
    public:
        enum { exists = sizeof (Test (MakeT ())) == sizeof (Small) };
        enum { sameType = 0 };
    };
    
    template <class T>
    class Conversion<T,T>
    {
    public:
        enum { exists = 1, sameType = 1 };
    };
    
    #define SUPERSUBCLASS(T, U) \
        (Conversion<const U*, const T*>::exists && \
        !Conversion<const T*, const void*>::sameType)
    

    Geht teilweise noch eleganter (z.B. ohne enums), aber ist ansonsten Klasse.
    Gibts auch in der Loki-Bibliothek.



  • Geht teilweise noch eleganter (z.B. ohne enums)

    Ob eleganter sei mal dahingstellt, aber ohne enums und dafür mit SFINAE geht es z.B. so in der Art:

    // check if T extends U
    // Note: Fails at compile-time if U is an inaccessible
    // of T.
    template <class T, class U>
    struct Extends {
    typedef char (&YesType)[1];
    typedef char (&NoType)[2];
    
    static YesType test(const volatile U*);
    static NoType test(const volatile void*);
    
    enum { value = sizeof(YesType) == sizeof(test(static_cast<T*>(0)))};
    
    };
    

    Solche Sachen sollte man imo aber nicht selbst implementieren sondern stattdessein eine ordentliche Bibliothek verwenden. boost::type_traits bietet sich hier natürlich an.



  • @Templator

    Den Test in der if-Bedingung müsstest du in diesem Fall durch Überladung ersetzen. In etwa so:

    template <int I> struct Int2Type {};
    
    template<class type1, class type2>
    class Hashtable{
    public:
        Hashtable();
        virtual ~Hashtable();
        // nicht virtuell, nur forwarding
        void put(type1 a, type2 b){
            doPut(a, b, Int2Type<Extends<type1, HashValue>::value>());
        }
    
        // für den Fall, dass type1 von HashValue erbt...
        virtual void doPut(type1, type2, Int2Type<1>);
        // ...andernfalls
        virtual void doPut(type1, type2, Int2Type<0>);
    };
    

    Eine (bessere) Alternative wäre die Verwendendung von boost::enable_if.



  • @HumeSikkins: funktioniert das auch wenn T private von U erbt (sprich gibt es dann no zurück)? Wenn ja, warum?
    /edit: ah, das meinst du mit erreichbar



  • Nur die öffentliche Vererbung erlaubt die implizite Umwandlung von Zeigern in Ableitungsrichtung (und damit funktionieren beide Tests). Das schrieb ich aber bereits :p


Anmelden zum Antworten