Parametertyp von Templatefunktion feststellen



  • 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);
    

  • Mod

    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.


  • Mod

    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 statt decltype(T().getHashCode()) decltype(std::declval<T>().getHashCode()) , aber das geht auch schöner mit dem AUTO_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 nix
    

    Irgendwie 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_if mit dem REQUIRES -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);
    }
    


  • deinvater schrieb:

    ...
    

    Natürlich, so geht das. Kopf->Tisch
    :Sone geht sich den Kopf verbinden, der jetzt zu bluten begonnen hat:

    @volkard: Ist natürlich doch SFINAE. Interessant, der Trick ist gut. Aber falsch angewendet, weil du DefaultConstructible forderst, was nicht sein muss.


  • Mod

    deinvater schrieb:

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

    Verstehe den Code nicht. Wie sollen denn die überzähligen Templateparameter in 2 und 3 bestimmt werden?



  • Sone schrieb:

    @volkard: Ist natürlich doch SFINAE. Interessant, der Trick ist gut. Aber falsch angewendet, weil du DefaultConstructible forderst, was nicht sein muss.

    Stimmt auffallend.
    War auch mehr so in die Luft schlampig geworfen, weil ich dachte, dieses Trennen ist das, was dem Threadersteller am meisten hilft. War mir sicher, ihr verbessert den Code. Hätte aber dazuschreiben sollen, daß das nur eine Skizze war.



  • camper schrieb:

    Verstehe den Code nicht. Wie sollen denn die überzähligen Templateparameter in 2 und 3 bestimmt werden?

    Oh, ich dachte, ich hätte das mal mit typename=void getestet, aber im Code von damals fehlen die entscheidenden Tests.

    Dann halt auch in C++11 der gute alte Trick mit der Extra-Funktion mit int - und ... -Überladung.



  • Sone schrieb:

    Irgendwie ist das Design auch kacke. Ich hätte da eher auf SFINAE mit

    template<typename T>
    struct HasGetHashCodeMethod
    

    Das hatte ich zuerst, aber innendrin ein wenig anders implementiert, nbämlich mit decltype(T().getHashCode()) in HasGetHashCodeMethod. Aber dann ist mir aufgefallen, daß ich im Prinzip nur den SF von decltype(T().getHashCode()) über mehrere komische Begriffe doch nur zum Return-Typ transportiere und hab's direkt hingeschrieben.


  • Mod

    deinvater schrieb:

    camper schrieb:

    Verstehe den Code nicht. Wie sollen denn die überzähligen Templateparameter in 2 und 3 bestimmt werden?

    Oh, ich dachte, ich hätte das mal mit typename=void getestet, aber im Code von damals fehlen die entscheidenden Tests.

    Dann halt auch in C++11 der gute alte Trick mit der Extra-Funktion mit int - und ... -Überladung.

    Bei 3 Varianten kann man auf Dummy-Argumente noch verzichten

    // 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... U>
    auto getHashCode(T const& t, const U&...) -> decltype(t.get_hash_code()) {
        return t.get_hash_code();
    }
    
    template <typename T, typename... U>
    T&& get_first(T&& x, U&&) {
        return std::forward<T>(x);
    }
    // Versuch 3: std::hash
    template <typename... T>
    auto getHashCode(T const&... t) -> decltype(std::hash<T>{}(get_first(t...))) {
        return std::hash<T>{}(get_first(t...));
    }
    

Anmelden zum Antworten