Typ-Unterscheidung bei statischer Polymorphie



  • Hallo zusammen,

    manchmal möchte man ja bei statischer Polymorphie ein anderes Verhalten für bestimmte Typen.
    Wie setzt ihr so etwas um?
    Mit Hilfe eines void*

    #include <iostream> 
    
    void shout_fussballclub(const void*){
    	std::cout << "Fußballclub";
    }
    
    void shout_fussballclub(const int*){
    	std::cout << "FC";
    }
    
    template<typename T>
    void shout(const T& t){
    	std::cout << "Erster ";
    	shout_fussballclub(&t);
    	std::cout << " Köln...";
    	std::cout << std::endl;
    }
    
    int main(){
    	shout("FC Köln");
    	shout("Meine");
    	shout("Nr.");
    	shout(1);
    }
    

    oder mit Template-Funktion:

    #include <iostream> 
    
    template<typename T>
    void shout_fussballclub(const T&){
    	std::cout << "Fußballclub";
    }
    
    void shout_fussballclub(const int){
    	std::cout << "FC";
    }
    
    template<typename T>
    void shout(const T& t){
    	std::cout << "Erster ";
    	shout_fussballclub(t);
    	std::cout << " Köln...";
    	std::cout << std::endl;
    }
    
    int main(){
    	shout("FC Köln");
    	shout("Meine");
    	shout("Nr.");
    	shout(1);
    }
    

    oder ganz anders?

    Erster Fußballclub Köln...
    Erster Fußballclub Köln...
    Erster Fußballclub Köln...
    Erster FC Köln...

    Also ich priorisiere (bisher) Version 2, weil man selbst in der Funktion noch die Typ-Info hat, die bei weiteren Funktionsaufrufen hilfreich sein kann.
    Hat man evtl. auch Nachteile damit?
    Was mir so einfällt - wo ich mich sehr wenig auskenne - ADL...
    Gibt es da ein unterschiedliches Verhalten von 'normalen' Funktionen gegenüber Template-Funktionen?

    Gruß,
    XSpille





  • An das Posting kann ich mich gut erinnern, verwende ich auch ab und zu,
    allerdings nur, wenn ich kein Objekt zur Verfügung habe.

    In dem 'Déjà-vu'-Posting habe ich ja nur einen typedef...

    EDIT:
    Und es macht natürlich Sinn, wenn man nur dieses Objekt separat behandeln möchte und keine abgeleiteten Klassen...
    Ein Anwendungsfall fällt mir im Moment nicht ein



  • In deinem Beispiel spielt doch auch nur der Typ eine Rolle, du hast ja keine Parametervariablen.

    Und ob du void* oder T nimmst, hängt vor allem davon ab, ob du die Typinformation brauchst und ob du Objekte/Referenzen oder Zeiger übergibst. Wobei du natürlich auch T* nehmen kannst. Bei void* sind keine separaten Instanziierungen notwendig, tendenziell ist der erzeugte Code also kleiner. Andererseits kannst du mit void* genauer steuern, was alles zur Überladungsauflösung genommen wird – ein

    template <typename T>
    void Func(T& t);
    

    wird für ziemlich viele Aufrufe ausgewählt, wenn kein besserer Match vorliegt.



  • Nexus schrieb:

    In deinem Beispiel spielt doch auch nur der Typ eine Rolle, du hast ja keine Parametervariablen.

    Hast du allerdings recht...
    Ich wollte das Beispiel nur ziemlich kurz halten und hab deswegen mit dem int nichts mehr gemacht...

    Nexus schrieb:

    Bei void* sind keine separaten Instanziierungen notwendig, tendenziell ist der erzeugte Code also kleiner.

    Würde ein halbwegs intelligenter Compiler nicht inlinen und somit gegen nichts ersetzen?

    Nexus schrieb:

    Andererseits kannst du mit void* genauer steuern, was alles zur Überladungsauflösung genommen wird

    Inwiefern "genauer steuern"? Also ein Zeiger ist er ja wegen des & immer und greift doch genau wenn das Funktions-Template auch greift, odeR?



  • XSpille schrieb:

    Würde ein halbwegs intelligenter Compiler nicht inlinen und somit gegen nichts ersetzen?

    Bei Inlining hast du nicht nichts, sondern sogar mehr Assemblercode, weil dieser bei jedem Funktionsaufruf dupliziert wird.

    XSpille schrieb:

    Inwiefern "genauer steuern"? Also ein Zeiger ist er ja wegen des & immer und greift doch genau wenn das Funktions-Template auch greift, odeR?

    Nein:

    #include <iostream>
    
    struct Base {};
    struct Derived : Base {};
    
    template <typename T>
    void X(T* t)     { std::cout << "T*" << std::endl; }
    void X(Base* t)  { std::cout << "Base*" << std::endl; }
    
    void Y(void* t)  { std::cout << "void*" << std::endl; }
    void Y(Base* t)  { std::cout << "Base*" << std::endl; }
    
    int main()
    {
    	Derived d;
    	X(&d);     // T*
    	Y(&d);     // Base*
    }
    

Anmelden zum Antworten