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