Parametertyp von Templatefunktion feststellen
-
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.
-
Zeig mal den Aufruf.
-
So:
template <typename TKey, typename TValue> int HashMap<TKey, TValue>::GetHashCode(const TKey* key) const { return reinterpret_cast<long>(key); } template <typename TKey, typename TValue> int HashMap<TKey, TValue>::GetHashCode(const TKey& key) const { return key.GetHashCode(); // C2228 } template <typename TKey, typename TValue> void HashMap<TKey, TValue>::Add(const TKey& key, const TValue& value) { ... int hashCode = GetHashCode(key) & 0x7fffffff; ... }
-
Warum machst du es nicht als freie globale Funktion?
-
Partielle Spezialisierung gibt es nur für Klassentemplates.
-
deinvater schrieb:
template <typename T> int getHashCode(T* t) { return reinterpret_cast<long>(t); }Will man ganz sicher gehen:
return reinterpret_cast<uintptr_t>(t);
-
Enumerator schrieb:
den Compilerfehler error C2228: Links von ".getHashCode" muss sich eine Klasse/Struktur/Union befinden.
Das ist sicher nicht die gesamte Fehlermeldung. Bestimmt teilt dir der Compiler auch noch mit, mit welchen Templateparametern die Instantiierung versucht wurde.
-
deinvater schrieb:
Warum machst du es nicht als freie globale Funktion?
Geht auch, aber ändert leider am Problem nichts.
Sone schrieb:
Partielle Spezialisierung gibt es nur für Klassentemplates.
Also bin ich jetzt wieder so schlau wie vorher :). Was ist denn ein Klassentemplate?
camper schrieb:
Enumerator schrieb:
den Compilerfehler error C2228: Links von ".getHashCode" muss sich eine Klasse/Struktur/Union befinden.
Das ist sicher nicht die gesamte Fehlermeldung. Bestimmt teilt dir der Compiler auch noch mit, mit welchen Templateparametern die Instantiierung versucht wurde.
Doch ist die ganze Fehlermeldung.
-
Enumerator schrieb:
camper schrieb:
Enumerator schrieb:
den Compilerfehler error C2228: Links von ".getHashCode" muss sich eine Klasse/Struktur/Union befinden.
Das ist sicher nicht die gesamte Fehlermeldung. Bestimmt teilt dir der Compiler auch noch mit, mit welchen Templateparametern die Instantiierung versucht wurde.
Doch ist die ganze Fehlermeldung.
Ich hoffe, du schaust dir das nicht bloss durch die IDE gefiltert an...
-
Vielleicht die Sachen ganz plump nebeneinanderlegen und mit SFINAE die Methoden ein wenig dämpfen.
#include <iostream> #include <string> using namespace std; template <typename T> decltype(T().getHashCode()) getHashCode(T const& t) { cout<<"methode\n"; return t.getHashCode(); } int getHashCode(std::string const& x){ cout<<"string\n"; return 0; } template <typename T> int getHashCode(T const* t) { cout<<"zeiger\n"; return reinterpret_cast<long>(t); } struct S {int getHashCode()const{return 0;}}; int main() { S s; getHashCode(s); getHashCode(&s); getHashCode(std::string("hallo")); // getHashCode(17);//hierfür gibts noch nix }
-
template <typename T> decltype(T().getHashCode()) getHashCode(T const& t) { cout<<"methode\n"; return t.getHashCode(); }lol

Erstmal stattdecltype(T().getHashCode())decltype(std::declval<T>().getHashCode()), aber das geht auch schöner mit demAUTO_RETURN-Makro:#define AUTO_RETURN(...) decltype(__VA_ARGS__) { return (__VA_ARGS__); } template<typename T> auto getHashCode(T const& t) -> AUTO_RETURN(t.getHashCode())Und kannst du mal erklären wo das SFINAE ist?
-
Sone schrieb:
Und kannst du mal erklären wo das SFINAE ist?
Hab das ählichste Wort genommen, was mir eingefallen ist. Wie heißt dieser Trick richtig?
-
volkard schrieb:
Wie heißt dieser Trick richtig?
SFINAE

Ich mag ein Upgrade davon, SFINAE plus ADL-Trick von boost::swap plus mit Prioritäten:
// Versuch 1: getHashCode() template <typename T> auto getHashCode(T const& t) -> decltype(t.getHashCode()) { return t.getHashCode(); } // Versuch 2: get_hash_code() template <typename T,typename> auto getHashCode(T const& t) -> decltype(t.get_hash_code()) { return t.get_hash_code(); } // Versuch 3: std::hash template <typename T,typename,typename> auto getHashCode(T const& t) -> decltype(std::hash<T>{}(t)) { return std::hash<T>{}(t); }
-
// getHashCode(17);//hierfür gibts noch nixIrgendwie ist das Design auch kacke. Ich hätte da eher auf SFINAE mit
template<typename T> struct HasGetHashCodeMethod { template<typename U, int(U::*)()> struct empty_type; template<typename U> static int16_t Test(empty_type<U,&U::used_memory>*); template<typename U> static int8_t Test(int); static std::integral_constant<bool, std::is_same<decltype(Test<T>(0)), int16_t>::value> value; };Und
std::enable_ifmit demREQUIRES-Makro:#define REQUIRES(...) ,class=typename std::enable_if<(__VA_ARGS__)>::type#include <type_traits> #include <cstdint> template<typename T> struct HasGetHashCodeMethod { template<typename U, int(U::*)() const> struct empty_type; template<typename U> static int16_t Test(empty_type<U,&U::getHashCode>*); template<typename U> static int8_t Test(...); static std::integral_constant<bool, std::is_same<decltype(Test<T>(nullptr)), int16_t>::value> value; }; #include <iostream> #include <string> using namespace std; #define REQUIRES(...) ,class=typename std::enable_if<(__VA_ARGS__)>::type #define AUTO_RETURN(...) decltype(__VA_ARGS__) { return (__VA_ARGS__); } template<typename T REQUIRES(HasGetHashCodeMethod<T>::value)> auto getHashCode(T const& t) -> AUTO_RETURN(t.getHashCode()) #include <functional> #include <typeinfo> template<typename T REQUIRES(!HasGetHashCodeMethod<T>::value)> int getHashCode( T const& t ) { return std::hash<T>()(t); } struct S {int getHashCode()const{return 0;}}; int main() { S s; getHashCode(s); getHashCode(&s); getHashCode(std::string("hallo")); getHashCode(17); }