Einführung in die Programmierung mit Templates



  • GPC schrieb:

    Okay, Abschnitt umgeschrieben 🙂

    Besser!

    Aber nur um bei den vorhandenen Beispielen zu bleiben und anhand eines Beispiels alles zu erklären könnte man die Überladung von minimum<>() auch für C-Strings zeigen.
    Also nach dem Motto:

    Eine echte Spezialisierung unseres minimum<>()-Templates für Strings würde demnach also so aussehen:

    template<>
    inline const char *&minimum(const char *&a, const char *&b) {
      return ((strcmp(a, b) < 0) ? b : a);
    };
    


  • Hem, ich dachte ich bring mal was anderes als das ausgelutschte minimum... aber in diesem Kontext verdeutlicht es die Spezialisierung wohl besser. 🙂



  • Sorry, aber mein Code war auch noch falsch.
    Dein Template verlangt "const T &", also eine konstante Referenz. Meine "char *"-Spezialisierung gibt ihm aber eine nicht-konstante Referenz auf einen Pointer auf einen const char. Sowas passiert, wenn man mal eben schnell ohne Compiler ein Template zusammensetzt und noch nicht ganz wach ist...
    Das Template mit Inline mit const und allem drum und dran wird für einen Anfänger in dieser Form vielleicht etwas haarig, aber richtig (und mit Erklärung) wäre die Spezialisierung für "char *" folgendermaßen:

    template<>
    inline const char *const &minimum(const char *const &a, const char *const &b) {
      return ((strcmp(a, b) < 0) ? b : a);
    };
    

    Man könnte zwar Denken, daß ein "const char *&a" ausreichen sollte, wenn man für T einfach stupide ein "char *" einsetzt, aber so denkt der C++-Standard nicht. Die Typen im generischen Template sind "const T&", was einer konstanten Referenz auf T entspricht. Wollen wir das gleiche mit einem Pointer erreichen, darf nicht das Ziel des Pointers const sein, sondern die Referenz. Somit würde eine Template-Spezialisierung für "char *" folgendermaßen aussehen:

    [cpp]template<>
    inline char *const &minimum(char *const &a, char *const &b) {
      return ((strcmp(a, b) < 0) ? b : a);
    };
    

    Die Typen entsprechen einer konstanten Referenz auf einen Zeiger auf einen char. Natürlich kann man dadurch den String selbst noch verändern, um also auch noch den char konstant zu deklarieren, benötigen wir das zweite const, was insgesamt den Typ "const char *const &" ergibt. Die Spezialisierung ist nun "template<const char *>minimum(), also eine Spezialisierung für "const char *" und nicht mehr nur für "char *".

    Ist zwar sehr verwirrend, aber durch "const T &" legst du ja schon relativ verwirrungsträchtig vor 😉

    Ist ein wenig ins Unreine geschrieben, die perfekte Integration in deinen Artikel überlasse ich dir (hängt auch davon ab, wie sehr du deinen Artikel über Templates auch die "const correctness" beleuchten lassen willst).



  • Sorry, aber mein Code war auch noch falsch.

    Tjo, mir ist's in der Eile auch nicht aufgefallen, das kommt von Copy & Paste^^

    Deine Erklärung ist gut, jedoch befürchte ich, dass es an der Stelle etwas zu viel wird, zum Einen das Template und dann noch die const-correctness (die ich übrigens in meinem Pointer-Artikel erläutert habe 🙂 ). Daher bin ich wieder auf das einfache Beispiel umgestiegen.

    Du bist ziemlich fit, was C++ angeht, besonders Templates... darf ich dich hierauf aufmerksam machen? Na wie sieht's aus, hättest du Zeit und Lust für den Artikel?

    MfG

    GPC



  • GPC schrieb:

    jedoch befürchte ich, dass es an der Stelle etwas zu viel wird

    Ja, ich auch.

    GPC schrieb:

    zum Einen das Template und dann noch die const-correctness (die ich übrigens in meinem Pointer-Artikel erläutert habe 🙂 ).

    Wenn die Geschichte mit Referenzen auf Konstanten in dem Artikel erklärt wird, würde ich für jeden, der wissen will, was "const char *const &" bedeutet, dorthin verlinken. Früher oder später wird man ohnehin const-correctness kapieren müssen 😉

    GPC schrieb:

    Du bist ziemlich fit, was C++ angeht, besonders Templates...

    Geht so. Ich scheine nur der einzige zu sein, der bei Diskussionen "C++ gegen den Rest der Welt" immer der Meinung ist, C++ habe eine einfach zu verstehende Syntax. 😃

    GPC schrieb:

    darf ich dich hierauf aufmerksam machen? Na wie sieht's aus, hättest du Zeit und Lust für den Artikel?

    Habe ich so noch nicht mit gearbeitet, aber die Beispiele im Wikipedia-Artikel haben was... (sind allerdings in dieser Formatierung ohne Highlighting ziemlich unleserlich ;)). Außerdem habe ich nicht vor, mir auch noch großartig Bücher zu kaufen. Und ich müsste mir erstmal einen Algorithmus aus den Fingern saugen, der vom Verständnis her einfach ist und der sich auch syntaktisch nicht allzu verwirrend in C++-Templates gießen lässt. Wie gesagt, schon für das Potenzierungs-Beispiel von Wikipedia brauchte ich einen Syntaxhighlighter und zweimaliges Lesen (die Fakultät im englischen Aritkel war da deutlich einfacher).
    Vielleicht kriege ich ja passende Beispiele serviert, wenn ich studiere.
    Aber ich biete mich gerne zum Gegenlesen an, wenn einer einen Artikel hat.



  • Hi,

    hab das gerade mal nen bisschen ausprobiert, aber folgendes verstehe ich nicht:

    #ifndef MY_CLASS_H
    #define MY_CLASS_H
    
    #include <iostream>
    
    template <typename T>
    class MyClass
    {
    	private:
    		T m_Element;
    
    	public:
    		MyClass( void ) { ; }
    		~MyClass( void ) { ; }
    
    		void setElement( T NewElement ) 
    		{ 
    			std::cout << "[Typ]NewElement: ???" << std::endl;
    			m_Element = NewElement; 
    		}
    
    		//template< > // Wie funktioniert das nun!?
    		void setElement( int NewElement ) 
    		{
    			std::cout << "[Typ]NewElement: int" << std::endl;
    			m_Element = NewElement; 
    		}
    
    		T getElement( void ) { return m_Element; }
    
    		void PrintElement( void ) 
    		{
    			std::cout << "Element: " << m_Element << std::endl; 
    		}
    };
    
    #endif /* MY_CLASS_H */
    

    Bei mir compiliert der Code, aber so solls ja glaube nicht gemacht werden, ohne das template < >?

    Danke

    Gruß



  • Was willst du überhaupt machen? Die Methode setElement für int spezialisieren?



  • Richtig. Genau das. Ich weiß, dass das schwachsinnig ist, aber irgendwie muss ich das ja ausprobieren nur klappt das nicht...

    /edit by GPC: nick gekürzt



  • Na ja, mir fehlt etwas der konkrete Anwendungsfall, aber wenn du z.B. den Code ausführst:

    //hier dein Code
    
    int main() {
      MyClass<float> fc;
      fc.setElement(2.5f);
      fc.setElement(2);
    }
    

    dann gibt's folgende Ausgabe:

    gpc@desktop:~$ g++ -o main main.cpp
    gpc@desktop:~$ ./main
    [Typ]NewElement: ???
    [Typ]NewElement: int
    

    Btw. Bitte verwende einen kürzeren Nick. Danke 🙂

    MfG

    GPC



  • So habe ich aber keine Spezialisierung sondern nur eine normale Überladung. Kann doch nicht richtig sein?



  • Stimmt, das ist Überladung. Da du aber ein Klassentemplate hast, kannst du auch nur das spezialisieren (partiell oder vollständig). D.h. entweder die Überladung oder du machst es so:

    //Generisch:
    template <typename T>
    struct Foo {
      T bar;
    
      void set_bar(const T &x) { bar = x; }
      const T& get_bar() const { return bar; }
    };
    
    //Für ints:
    template <>
    struct Foo<int> {
      //hier spezialisierte Versionen der Methoden von oben
    };
    

    Damit hast du allerdings die Klasse spezialisiert.

    Template-Methoden spezialisieren geht auch, aber dann brauchst du template-Methoden.



  • btw, SFINAE steht für substitution failure is not an error



  • Magst du evtl noch die Syntax für Template-friend-Deklarationen mit reinnehmen? Solche speziellen Sachen vergess ich immer, brauch's ja auch fast nie 🙂 edit: Hier meine ich template<typename[,...]> friend class XYZ;
    Achso, und magst du vielleicht auch noch mal explizit reinschreiben, dass es keine partiell spezialisierten Funktionen gibt? Hatte neulich vergessen, dass es nur mit Klassen geht und mir 'nen Wolf gesucht 😃



  • Kann ich machen, aber nach der Klausurphase...


Anmelden zum Antworten