Template spezialisierung ohne template?



  • Hallo,

    ich bin etwas verwirrt und verstehe nicht wie man üblicherweise methoden die template-spezialisierend sind ohne einen template-parameter instantiieren kann/soll.

    wie macht ihr das?

    Ich möchte folgendes:

    template <class T>
    class MyTClass
    {
           void foo();
    };
    
    #include "MyTClass.imp.h"
    
    //MyTClass.imp.h
    template <>
    MyTClass<double>::foo()
    {
            // do something
    }
    

    was so nicht geht in der main einfach myClass.foo() zu machen.

    vielmehr mache ich es im moment so (was auch funktioniert) aber ich nicht weiß obs sauber ist - ich fidne es etwas seltsam:

    //MyTClass.imp.h
    template <>
    MyTClass<double>::foo(MyTClass<double> *irgendwas)
    {
            // do something
    }
    

    und der aufruf sieht dann z.B. so aus:

    MyTClass<double> x;
    
    x.foo(x);
    

    Also ich rufe vom objekt die methode auf die aber als paramter das objekt selber hat? Seltsam oder nicht?

    danke für eure hilfe



  • Du könntest default Template Argumente angeben.
    Simon

    Edit: hat glaube ich nichts mit deinem Problem zu tun... aber wissenswert ist es allemal.



  • Verstehe Dein Problem nicht so recht. So?

    template<typename T>
    class Test
    {
    public:
        void foo(){ std::cout << "foo<T>()\n"; }
    };
    
    template<>
    class Test<double>
    {
    public:
        void foo(){ std::cout << "foo<double>()\n"; }
    };
    
    int main()
    {
        Test<int> t1;
        Test<double> t2;
    
        t1.foo(); //Ausgabe: foo<T>()
        t2.foo(); //Ausgabe: foo<double>()
    }
    


  • @ tachyon: eh nein nicht ganz

    template<typename T>
    class Test
    {
    public:
        void foo(Test<double> t);
       void foo(Test<int> t);
    
    };
    
    //Test.cpp
    #include "Test.h"
    
    template<> void Test<double>::foo(Test<double> t)
    { std::cout << "foo<double>()\n"; }
    
    template<> void Test<int>::foo(Test<int> t)
    { std::cout << "foo<int>()\n"; }
    
    int main()
    {
        Test<int> t1;
        Test<double> t2;
    
        t1.foo(); //Ausgabe: foo<int>()
        t2.foo(); //Ausgabe: foo<double>()
    }
    

    Was sind default template-argumente und wie benutzt man diese?



  • was so nicht geht in der main einfach myClass.foo() zu machen.

    natürlich geht das.
    bloss dass du wohl nicht 1:1 deinen code hier gepostet hast.

    hat aber kaum jemand hier lust zu raten.

    vermutlich hast du ein funktions-template, und nicht wie hier beschrieben ein klassen-template.



  • selbstverständlich habe ich nicht 1:1 code gepostet. Soll ihc jetzt 10000 LOCs posten oder wie?

    Ich habe ein Klassentemplate und in dieser klasse soll es aber eine funktion zur ausgabe geben. Da aber die ausgabe template-typ abhängig ist habe ich template-spezialisierungen benutzt. Nur kann ich ja nicht ein
    template<> void Test<double>::print_data() ohne template typ verwenden
    oder doch?



  • Mati schrieb:

    ...Nur kann ich ja nicht ein
    template<> void Test<double>::print_data() ohne template typ verwenden
    oder doch?

    Nur mal zum Verständnis: Du hast ein allgemeines Template (nicht spezialisiert). Und nur die Methode zur Ausgabe soll spezialisiert sein. Der Rest soll weiterhin generisch bleiben. Verstehe ich das richtig?



  • Nur mal zum Verständnis: Du hast ein allgemeines Template (nicht spezialisiert). Und nur die Methode zur Ausgabe soll spezialisiert sein. Der Rest soll weiterhin generisch bleiben. Verstehe ich das richtig?

    Ja richtig.



  • Warum machst Du dann kein Function Template?
    (Oder wenn die Impl. vom Argument Typ anhängig ist eine Überadung..)

    Simon



  • Warum machst Du dann kein Function Template?
    (Oder wenn die Impl. vom Argument Typ anhängig ist eine Überadung..)

    nichts für ungut und danke für die Hilfe aber genau deswegen habe ich gepostet...ich weiß eben nicht wie ich es machen soll und mir fehlt auch ein beispiel damit ich es verstehe...



  • Er.
    Also nochmal langsam.
    Was du schreibst (die Variante die angeblich nicht geht), GEHT.
    Abgesehen davon dass du bei der Spezialisierung den Return-Typ vergessen hast, was natürlich dann kein Compiler mehr fressen wird.

    Ganz konkret, dieser Code funktioniert wie erwartet:

    #include <iostream>
    
    template <class T>
    class foo
    {
    public:
    	void aaa()
    	{
    		std::cout << "aaa (generic)\n";
    	}
    
    	void test();
    };
    
    // foo::test spezialisierung für foo<double>
    template <>
    void foo<double>::test() // du hast das "void" hier vergessen, was ja wohl nicht gehen kann
    {
    	std::cout << "test (double)\n";
    	aaa();
    }
    
    // foo::test spezialisierung für foo<int>
    template <>
    void foo<int>::test()
    {
    	std::cout << "test (int)\n";
    	aaa();
    }
    
    int main(int argc, char** argv)
    {
    	foo<double> fd;
    	foo<int> fi;
    
    	fd.test();
    	fi.test();
    
    	return 0;
    }
    

    output ist

    test (double)
    aaa (generic)
    test (int)
    aaa (generic)
    

    selbstverständlich habe ich nicht 1:1 code gepostet. Soll ihc jetzt 10000 LOCs posten oder wie?

    Nein. Du sollst ein Minimal-Beispiel machen, compilieren, und dann inklusive der Compiler- bzw. Linker-Fehlermeldungen posten. Oder, falls es compiliert & linkt, aber das falsche Ergebnis liefert: das erwartete Ergebnis sowie das beobachtete Ergebnis posten (idealerweise Output eines Konsolenprogramms, wie das von mir gezeigte Beispiel).
    Und zwar 1:1 den Code des Minimal-Beispiels posten, und nicht mal eben irgendwas in den Browser reinhacken, wobei du dann 10 andere Fehler machst.

    (Es ist immer ganz toll, wenn man jmd. auf einen Fehler in seinem Code aufmerksam macht, und der dann antwortet "ja blah, das is ja nur hir in forum faltsch, in mein toller programm is DAS eh richtick, muss also liegt an wahs anderen, harhar")

    Genau das (1:1 Code + Fehlermeldung posten) hast du nicht gemacht. Hättest du es gemacht, hättest du vermutlich auch viel schneller eine hilfreiche Antwort erhalten.

    Verstehst du jetzt worauf ich hinaus wollte?



  • Danke für die ausführliche antwort. Ich habe alles verstanden und versuche in zukunft minimalbeispiele aufzusetzen.

    Weitere Frage:
    Wenn ich eine Methode in einer Template-basierten KLasse habe die ich aufrufen möchte noch bevor ich weiß welche template-typen die klasse haben wird - dann bin ich doch gezwungen einfach dummy-typen zu nehmen oder?

    Also ich möchte sowas schaffen:

    #include <iostream>
    
    template <class T>
    class foo
    {
    public:
        void bar()
    };
    
    template <class T>
    void foo<T>::bar() 
    {
        std::cout << "bar()";
    }
    
    int main(int argc, char** argv)
    {
        foo<double> fd;
    
        fd.bar();
    
        return 0;
    }
    

  • Mod

    Mati schrieb:

    Weitere Frage:
    Wenn ich eine Methode in einer Template-basierten KLasse habe die ich aufrufen möchte noch bevor ich weiß welche template-typen die klasse haben wird - dann bin ich doch gezwungen einfach dummy-typen zu nehmen oder?

    Verstehe ich nicht. Kannst du mal ein Beispiel geben? Eigentlich sollte man nie dummy-Typen nötig haben.

    Also ich möchte sowas schaffen:
    [...]

    Und? Funktioniert doch schon so. Gibt bar() aus.



  • Hmm - ich habe mein design umgestellt und so geht es. Folgende Frage beschäftigt mich aber: Kann ich eine Templatespezialisierung aus einer templatebasierten klasse aufrufen?

    Also sowas:

    //foo.h

    #include <iostream>
    
    template <class T>
    class foo
    {
            public:
                    void bar();
                    void myfunction(int var);
                    void myfunction(double var);
    };
    
    template <class T>
    void foo<T>::bar()
    {
            int var = 9;
            std::cout << "bar()";
            myfunction(var);
    }
    

    //foo.cpp

    // die foo.cpp
    #include "foo.h"
    
    template<>
    void foo<int>::myfunction(int a)
    {
            std::cout << "myfunction int";
    }
    template<>
    void foo<double>::myfunction(double a)
    {
            std::cout << "myfunction double";
    }
    

    und die main.cpp

    #include "foo.h"
    
    // die main
    
    int main(int argc, char** argv)
    {
            foo<double> fd;
    
            fd.bar();
    
            return 0;
    }
    

    Der Fehler der ensteht ist folgender:

    warning: no newline at end of file
    main.cpp:16:2: warning: no newline at end of file
    /tmp/ccS0tURA.o: In function `foo<double>::bar()':
    main.cpp:(.text._ZN3fooIdE3barEv[foo<double>::bar()]+0x2f): undefined reference to `foo<double>::myfunction(int)'
    collect2: ld gab 1 als Ende-Status zurück
    

    Geht das nicht?



  • Naja. Steht ja in der Fehlermeldung.

    Die Funktion mit der Signatur:

    void foo<double>::myfunction(double a)
    

    wird nicht instanziert. Du hast ja lediglich

    void foo<int>::myfunction(int a)
    

    Da du aber foo<double> hast geht das nicht.



  • bin ihc jetzt blöd? Ich seh meinen fehler nicht.
    Geht das nicht weil ichs falsch hab oder gehts allgemein nicht?

    aber auch so gehts nicht:

    // die foo.cpp
    #include "foo.h"
    
    template<>
    void foo<int>::myfunction(int& a)
    {
            std::cout << "myfunction int";
    }
    template<>
    void foo<double>::myfunction(double& a)
    {
            std::cout << "myfunction double";
    }
    
    #include <iostream>
    
    template <class T>
    class foo
    {
            public:
                    void bar();
                    void myfunction(int& a);
                    void myfunction(double& a);
    };
    
    template <class T>
    void foo<T>::bar()
    {
            T var; 
            std::cout << "bar()";
            myfunction(var);
    }
    


  • Für foo<double> hat myfunction(int) lediglich eine Deklaration jedoch keine Definition. Du versuchst aber in foo<double>::bar() foo<double>::myfunction(int) aufzurufen. Da fehlt jedoch der Rumpf...



  • 🙂 genau das will ich ja erreichen- geht sowas nicht? Muss ich da für jeden T-typen eine leere template-spezialisierungs funktion anlegen?

    Doch wie kann ich innerhalb eine template-funktion abhängig vom Template-Typen in Template-spezialisierungen unterschiedlicher signatur springen? Muss ich wirklich für alle typen identische signatur-templates zur verfügung stellen die dann leer sind? so dummy template-spezialisierungen?



  • template <class T> 
    class foo 
    { 
            public: 
                    void bar(); 
                    void myfunction(T& a); 
    };
    

    😕


Anmelden zum Antworten