klasse nicht geklariert, obwohl sie es sein müsste?!



  • na wenn ich templates habe brauch ich die definitionen der einzelnen funktionen sonst meckert er ja auch rum.



  • Ja dann musst du dich eben drum kümmern dass die definition verfügbar ist. Wie gesagt liegt das Problem in deinen zirkulären includes, denk mal drüber nach was du da eigentlich tust...



  • mir ist das schon klar das ich zirkulär inklude, was allerdings durch IncludeGuards kein Problem sein sollte.
    es ist halt so das lgs nur diverse funktionen, die auf mat-objekten arbeiten zur verfügung stellt. für ein paar methoden von mat brauche ich diese funktionen aus lgs und möchte die halt dort nutzen. wie kann ich dass denn dann sinnvoll umsetzen, wenn nicht so?



  • FreakyBKA schrieb:

    mir ist das schon klar das ich zirkulär inklude, was allerdings durch IncludeGuards kein Problem sein sollte.

    Genau da liegt dein Trugschluss. Es ist eben doch ein Problem...

    Wie gesagt:

    dot schrieb:

    Include Guards sind kein Freibrief um einfach abschalten und alles überall inkludieren zu können...



  • Bei Klassentemplates ist es durchaus eine Möglichkeit, die Definitionen der Memberfunktionstemplates in eine .cpp zu packen, und die in der .h (aber dann auch nur da) zu includieren.
    Das wird auch hier beschrieben: http://www.amazon.com/Templates-Complete-Guide-David-Vandevoorde/dp/0201734842
    Allerdings hat es dich (schon allein der Übersichtlichkeit halber) durchgesetzt, dass man die Definitionen einfach mit in die .h schreibt, die cpp nicht includiert und da nur den Kram drin hat, der nicht sichtbar sein muss. Dann passt es auch wieder zum normalen .h-.cpp-Konzept. Das würde ich auch empfehlen.
    Warum dein Beispiel hier allerdings nicht kompiliert werden kann, versteh ich nicht. Habs gerade hier mit VC 2005 Express probiert, und da ging es fehlerfrei.
    Muss es ja eigentlich auch, denn wenn man manuell das macht, was der Präprozessor in dem Fall mit den includes macht, kommt folgendes bei raus:

    template<class t>
    class mat
    {
        public:
            t _data;
            void change(t const &data);
    };
    
    class lgs
    {
        public:
            template<class t>
            static void change(mat<t> &m, t const &data);
    };
    
    template<class t>
    void lgs::change(mat<t> &m, t const &data)
    {
        m._data = data;
    }
    
    template<class t>
    void mat<t>::change(t const &data)
    {
        lgs::change(*this, data);
    }
    

    Kann es sein, dass du in deine Code doch noch irgendwo etwas anders hast als bei dem, was du hier gepostet hast?



  • ja und das genaue Problem suche ich halt.
    die idee ist halt das ich folgende reihenfolge habe

    deklaration mat und lgs
    definition mat und lgs

    und wenn ich das durchspiele kommt das doch auch überall so hin, oder nicht?



  • Dobi schrieb:

    Kann es sein, dass du in deine Code doch noch irgendwo etwas anders hast als bei dem, was du hier gepostet hast?

    ich hab es genauso wie oben compiliert, mit GNU GCC, und da gibt er besagten fehler. mein eigentlicher code ist komplexer, aber konnte den gleichen fehler halt auch mit dieser vereinfachten variante konstruieren, also muss er auch hier zu finden sein.



  • Überleg mal was Include Guards machen:

    // A.h
    
    #ifndef A_INCLUDED
    #define A_INCLUDED
    
    #include "B.h"
    
    class A
    {
    };
    
    #endif
    
    // B.h
    
    #ifndef B_INCLUDED
    #define B_INCLUDED
    
    #include "A.h"
    
    class B
    {
      A a;
    };
    
    #endif
    

    Du inkludierst irgendwo A.h. A_INCLUDED wird definiert und dann gleich drauf B.h inkludiert. B.h inkludiert nun wieder A.h. Da A_INCLUDED aber schon definiert ist kommt nix aus A.h mehr rein und der Typ A ist in B.h undefiniert. Die Moral von der Geschicht: Include Guards lösen nicht auf irgendeine magische Art und Weise zirkuläre Abhängigkeiten auf.



  • sehe ich nicht so, denn bei mat.h wir lgs.h nach der deklaration von mat inkludiert, weswegen es eigentlich funktionieren müsste.



  • Im Beispiel von dot kann man zirkuläre Abhängigkeiten lösen, indem man eine Vorwärtsdeklaration macht.

    Aus

    #include "A.h"
    

    wird

    class A;
    

    .

    Wenn A.h bereits inkludiert ist, dann findet man in B.h nur eine leere Datei (dank Inkludeguards). Somit kann es nicht funktionieren.



  • VC hats eben wie gesagt ohne zu meckern übersetzt. Ich konnte mir zwar nicht vorstellen, dass GCC das nicht schafft, habs dann aber trotzdem getestet. Ergebnis: Auch da funktionierts. Siehe hier: http://i51.tinypic.com/28vatl5.png
    Den Fehler, dass er kein main findet, wird man natürlich los wenn man das hier macht:
    http://i51.tinypic.com/2ccqvxg.png
    Offensichtlich hast du also doch noch irgendwo was anderes falsch. 😉
    Aber selbst wenn du es findest, empfehle ich in jedem Fall weiterhin, die Definitionen mit in die .hs zu packen, weil es dann einfach viel übersichtlicher wird. 🙂



  • Das Problem is ja auch nicht dass mat unbekannt ist sondern lgs. Wenn du z.B. mit #include "lgs.h" startest dann wird als erstes gleich mal mat.h inkludiert welches nach der Definition von mat lgs inkludiert, was nun aber übersprungen wird und dazu führt dass in der Definition von mat<t>::change() lgs unbekannt ist.

    Abgesehen davon kann man das mit der Trennung von Deklaration und Implementierung schon so machen nur würde ich dazu raten die Dateien dann eben nicht .cpp zu nennen sondern irgendwas anderes.



  • @Dot: Schau dir doch nochmal genau an, was er da tut, und was der Präprozessor mit seinem Code dann macht. Seine Vorgehensweise ist nicht falsch (Es funktioniert ja, siehe meine Screenshots) sondern nur unnötig kompliziert. 😉
    Dieses Verfahren ist halt ein gescheiterter Versuch, auch bei Templates noch alle Definitionen in eine cpp zu packen.
    Wenn da jetzt noch andere Memberfunktionen dabei wären, die nicht templatig sind, müssten die konsequenterweise in eine weitere cpp kommen, die dann nirgendwo includiert wird und wie bei Nichttemplategeschichten auch dann erst von Linker drangeknotet wird.



  • ok, das stimmt, bin immer von #include "mat.h" ausgegangen, dann müsste ja eine forward-deklaration von mat in lgs.h punkt abhilfe schaffen.



  • hat funktioniert, danke für die hilfe



  • Darf ich die Auflösung erfahren, warum der gepostete Code bei mir lief und bei dir nicht? 🙂



  • Dobi schrieb:

    Darf ich die Auflösung erfahren, warum der gepostete Code bei mir lief und bei dir nicht? 🙂

    Vermutlich weil du mat.h inkludiert hast und nicht lgs.h



  • ja denke auch das daran lag, hab die lgs.h jetzt jedenfalls zu

    #ifndef __lgs_h__
    #define __lgs_h__
    
    template<class t>
    class mat;
    
    class lgs
    {
    	public:
    		template<class t>
    		static void change(mat<t> &m, t const &data);
    
    };
    
    #include "mat.h"
    
    #include "lgs.cpp"
    
    #endif
    

    geändert und es funktioniert.



  • dot schrieb:

    Dobi schrieb:

    Darf ich die Auflösung erfahren, warum der gepostete Code bei mir lief und bei dir nicht? 🙂

    Vermutlich weil du mat.h inkludiert hast und nicht lgs.h

    Ich hatte nix geändert sondern nur den Code, der im Eingangspost stand, in Dateien kopiert, was man auch auf den Screenshots sieht. Naja, mir solls egal sein. 😉



  • Um den Code zu verwenden musst du ihn ja aber in irgendeine Übersetzungseinheit inkludieren. Oder hast du dich von der Tatsache verwirren lassen dass die beiden Dateien mit den Implementierungen auf .cpp enden? Genau darum halte ich es wie gesagt auch für eine extrem schlechte Idee Dateien auf .cpp zu benennen die gar keine Übersetzungseinheiten sind 😉


Anmelden zum Antworten