Parametertyp von Templatefunktion feststellen
-
Auch das geht. Aber du willst auch das nicht.
Wenn du schon einen Pointer hast => DAS IST DEIN HASH!!! Deine Hashfunktion ist garantiert schlechter als ein Pointer, der 1. garantiert unique und 2. ohne Berechnung verfügbar ist.
Noch besser ist allerdings <boost/unordered_map> oder <tr1/unordered_map> oder <unordered_map> (C++11) einzubinden und davon zu profitieren. Da ist dein Hashproblem schon gelöst.
-
deinvater schrieb:
Die Suggeration vom Sohne geht erst mit static-ifs.
Ähm...nein!?
-
Nathan schrieb:
deinvater schrieb:
Die Suggeration vom Sohne geht erst mit static-ifs.
Ähm...nein!?
Zeig mal wie du das ohne Dispatch machst.
-
Na mit ifs?
http://ideone.com/YI1x5J
-
Das war ja auch meine Idee. Da die Adresse des Zeigers einmalig ist. Aber wie stelle ich das jetzt an? Folgende Funktion:
template <class TKey, class TValue> void HashMap<TKey, TValue>::Add(const TKey& key, const TValue& value) { ... int hashCode = /* hier brauche ich den HashCode*/ & 0x7fffffff; ... }Woher bekomme ich nun den HashCode bzw. woher weiß ich, dass "key" ein Zeiger oder Objekt ist?
-
Aha. http://ideone.com/xLjXxZ. Schonmal an den Fall vom OP gedacht?
-
Ja, du wirst so nicht arbeiten können, denn der Code wird nun einmal - sobald das Template instantiiert wird - komplett geschluckt und geprüft.
Wenn du bei Memberfunktionen in Klassentemplates Unterscheidung für mehrere verschiedenen Template-Parameter haben willst, nutze einen Trick. Das Int-To-Type Idiom.
Das ist eine hingekotzte Version, das geht bestimmt schöner:
#include<iostream> template<typename TParam> class MyClass { /// Definition für Referenzen void MyFunction( TParam const&, std::integral_constant<bool, false>, std::integral_constant<bool, true> ); /// Definition für Zeiger void MyFunction( TParam const&, std::integral_constant<bool, true>, std::integral_constant<bool, false> ); public: void MyFunction( TParam const& param ) { MyFunction(param, std::integral_constant<bool, std::is_pointer<TParam>::value>(), std::integral_constant<bool, std::is_reference<TParam>::value>()); } }; template <class TParam> void MyClass<TParam>::MyFunction(const TParam& param, std::integral_constant<bool, false>, std::integral_constant<bool, true>) { param << "Lol"; } template <class TParam> void MyClass<TParam>::MyFunction(const TParam& param, std::integral_constant<bool, true>, std::integral_constant<bool, false>) { (*param) << "Lol"; } int main() { MyClass<std::ostream*>().MyFunction(&std::cout); MyClass<std::ostream&>().MyFunction(std::cout); }Edit: Jup, hier wird das schöner gemacht - sieh dir das Beispiel an: http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Int-To-Type
-
deinvater schrieb:
Wenn du schon einen Pointer hast => DAS IST DEIN HASH!!!
Das heißt, für gleiche Pointees gibt es unterschiedliche Hashwerte? Lol!
-
template <typename T> int getHashCode(T* t) { return reinterpret_cast<long>(t); } template <typename T> int getHashCode(T& t) { return t.getHashCode(); } struct S {int getHashCode()const{return 0;}}; int main() { S s; getHashCode(s); getHashCode(&s); }
-
deinvater schrieb:
Aha. http://ideone.com/xLjXxZ. Schonmal an den Fall vom OP gedacht?
Nö.
Nur bis "wie kann ich zwischen Pointer und nicht Pointer unterscheiden gelesen". Und das geht so.
*duck und weg*Edit:
Sone schrieb:
deinvater schrieb:
Wenn du schon einen Pointer hast => DAS IST DEIN HASH!!!
Das heißt, für gleiche Pointees gibt es unterschiedliche Hashwerte? Lol!
Schaue dir mal die std::hash<T*> Implementierung deines Compilers an. Oh.
-
Sone schrieb:
deinvater schrieb:
Wenn du schon einen Pointer hast => DAS IST DEIN HASH!!!
Das heißt, für gleiche Pointees gibt es unterschiedliche Hashwerte? Lol!
Es handelt sich um "nicht kopierbare Objekte habe (z.B. GUI-Controls)". Für nicht kopierbare Objekte ist die Identität an den Speicher gekoppelt. Ohne Ausnahme.
-
Upsi, ich habe mich vertan, ich dachte an was anderes, du hast Recht

Sone schrieb:
" 9
Sone schrieb:
deinvater schrieb:
Wenn du schon einen Pointer hast => DAS IST DEIN HASH!!!
Das heißt, für gleiche Pointees gibt es unterschiedliche Hashwerte? Lol!
Schaue dir mal die std::hash<T*> Implementierung deines Compilers an. Oh.
Schon klar. Ich habe das völlig missverstanden, ich dachte es ging um was anderes. Natürlich ist der Hash eines Zeigers sein Wert.
So wie halt für jeden Skalar sein Wert sein Hash ist.
-
Sone schrieb:
std::integral_constant<bool, true>, std::integral_constant<bool, false> std::integral_constant<bool, std::is_pointer<TParam>::value>(), std::integral_constant<bool, std::is_reference<TParam>::value>());lol?
1. std::true_type/std::false_type
2. typename std::is_pointer<T>::type/typename std::is_reference<T>::type
-
deinvater schrieb:
template <typename T> int getHashCode(T* t) { return reinterpret_cast<long>(t); } template <typename T> int getHashCode(T& t) { return t.getHashCode(); } struct S {int getHashCode()const{return 0;}}; int main() { S s; getHashCode(s); getHashCode(&s); }Ok, das schaut schonmal gut aus. Jetzt weiß ich aber immer noch nicht, ob "key" ein Zeiger oder Objekt ist. Also welche der GetHashCode-Funktionen ich aufrufen muss.
-
Enumerator schrieb:
deinvater schrieb:
template <typename T> int getHashCode(T* t) { return reinterpret_cast<long>(t); } template <typename T> int getHashCode(T& t) { return t.getHashCode(); } struct S {int getHashCode()const{return 0;}}; int main() { S s; getHashCode(s); getHashCode(&s); }Ok, das schaut schonmal gut aus. Jetzt weiß ich aber immer noch nicht, ob "key" ein Zeiger oder Objekt ist. Also welche der GetHashCode-Funktionen ich aufrufen muss.
Das überlässt du dem Compiler.
Bei
getHashCode(<irgendetwas>)wird automatisch die richtige Überladung ausgewählt.
-
Zudem hat es den Vorteil, dass du es leicht erweitern kannst. Es genügt,
int getHashCode(std::string const& s) { return std::hash<std::string>()(s); }hinzuzufügen und schon kann dein Container Strings unterstützen.
-
deinvater schrieb:
Sone schrieb:
std::integral_constant<bool, true>, std::integral_constant<bool, false> std::integral_constant<bool, std::is_pointer<TParam>::value>(), std::integral_constant<bool, std::is_reference<TParam>::value>());lol?
1. std::true_type/std::false_type
2. typename std::is_pointer<T>::type/typename std::is_reference<T>::typeJa, so kann man es abkürzen. Kopf->Tisch
Allerdings versagt die Methode, sobald mehr Unterscheidungen im Spiel sind.
Da würde ich es machen wie das Beispiel auf Wikibooks.
-
-
deinvater schrieb:
Zudem hat es den Vorteil, dass du es leicht erweitern kannst. Es genügt, [...] hinzuzufügen und schon kann dein Container Strings unterstützen.
Du musst aber aufpassen. Deine Templates sind gierig, sie unterbinden implizite Konvertierungen.
getHashCode("text")geht zum Beispiel schon mal nicht.Auch wenn du z.B. für
longerweiterst und mit einemintaufrufst, wird die allgemeine Version als Überladung ausgewählt. Das kann eventuell unintuitiv sein.
-
deinvater schrieb:
Das überlässt du dem Compiler.
Bei
getHashCode(<irgendetwas>)wird automatisch die richtige Überladung ausgewählt.
Habe mal versucht es so zu lösen, allerdings bekomme ich nun bei folgender Funktion
template <typename T> int getHashCode(T& t) { return t.getHashCode(); }den Compilerfehler error C2228: Links von ".getHashCode" muss sich eine Klasse/Struktur/Union befinden.