Announcement

Collapse
No announcement yet.

Template Methode in einer Klasse

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Template Methode in einer Klasse

    Hi!<br>

    Habe ein eigentlich einfaches Problem:<br>

    Datei test.h:<br>

    -------------<br>

    class CTest<br>

    {<br>

    public:<br>

    ...<br>

    private:<br>

    template <class T><br>

    void DoSomething( T & rtValue );<br>

    }<br>

    Die Methode "DoSomething" soll jetzt im CPP-File (!!!) ausimplementiert werden - geht aber nicht! Weiß jemand wie man dass bewerkstelligen kann? ich möchte nicht makros verwenden und ein drittes cpp file schreiben (so gehts nämlich) und schon gar nicht die methode im header ausimplementieren, da ich ziemlich große klassen habe und das ganze sonst unübersichtlich wird!<br>

    HHIIILLLFEE!<br>

    mfg<br>

    alexander walentin<br>

  • #2
    <b>Die Methode "DoSomething" soll jetzt im CPP-File (!!!) ausimplementiert werden - geht aber nicht! Weiß jemand wie man dass bewerkstelligen kann?</b><br>
    Gar nicht, zumindest mit derzeitigen Compilern noch nicht (höchstens Comeau vielleicht, VC++ jedenfalls nicht). Eine Template-Funktion muss im Header implementiert werden, weil --seeeehr verkürzt dargestellt-- der Compiler bei jeder Instantiierung der Funktion daraus erstmal templatefreien C++-Code erzeugt, den er dann schnell mal "normal" compiliert. D.h. wenn du irgendwo test.DoSomething(doubleVar) aufrufst, kannst du dir vorstellen, dass der Compiler sich deine Template-Funktion schnappt, sie temporär irgendwohin kopiert, in der Kopie jedes "T" durch "double" ersetzt und die modifizierte Kopie compiliert. Und dafür braucht er den kompletten Code der Funktion, nicht nur ihren Prototyp.
    <p>So, jetzt hab ich dich hoffentlich nicht mehr verwirrt als erhellt. :-)
    <br>Ciao, Uli

    Comment


    • #3
      Hi! <br>
      <br>
      Ich habe das Problem folgendermaßen gelöst: <br>
      <br>
      test.h: <br>
      ------- <br>
      <br>
      ... <br>
      <PRE>
      #ifdef _TEMPLATE_MEMBER_OK
      #define TEMPLATE(Param) template< param >
      #define CLASS(Param) Param ::
      #else
      #define TEMPLATE(Param)
      #define CLASS(Param)
      #endif
      <PRE>
      template < class A >
      class CTest
      {
      public: ...

      #ifdef _TEMPLATE_MEMBER_OK
      template < class T >
      void DoSomething( T & rtValue);
      #else
      #include "Test_tmpl.cpp"
      #endif
      };
      #include "Test.cpp"

      #ifdef _TEMPLATE_MEMBER_OK
      #include "Test_tmpl.cpp"
      #endif
      </PRE>
      <br>... <br>
      <br>
      <br>
      test.cpp: hier stehen die NICHT-template member methoden drinnnen
      <br>
      (ganz normal halt), konstruktor, etc <br>
      <br>
      <br>
      test_tmpl.cpp:<br>
      -------------- <br>
      <PRE>
      TEMPLATE ( class A)
      template < class T >
      void
      CLASS ( CTest<A> ) DoSomething( T &rtValue )
      {
      rtValue *= 2;
      }
      </PRE>

      entspricht zwar keinem objektorientierten Ansatz wegen der Makros
      (aber was ist bei MS schon objektorientiert? die MFC - nicht
      wirklich...) aber es funktioniert und man hat keinen Header der
      elendslang ist wenn man mehrerer solcher Funktionen benutzt!

      eigentlich ist mir unklar wie so eine einfache Sache die zB unter
      Linux und dem gcc compiler wunderbar funktioniert in einem so
      mächtigen Tool wie Visual C++ bzw Visual Studio .net nicht
      funktioniert!?!?!?!?! <br>
      <br>
      was soll man machen - besser als nix is die variante auf alle
      fälle!<br> <br>

      ciao <br>
      alex

      Comment


      • #4
        Ich hab mich jetzt nicht in den obigen Präprozessorverhau ;-) reingedacht,
        aber die Sache ist doch ganz einfach: Die Implementation von Templates
        muss mit in den Header, entweder innerhalb:<pre>
        class CTest
        {
        ...
        template <class T>
        void DoSomething( T & rtValue )
        {
        // Mach was mit rtValue
        }
        }
        </pre> oder außerhalb der Klassendeklaration:<pre>
        class CTest
        {
        ...
        template <class T>
        void DoSomething( T & rtValue );
        }
        <br>
        // Immer noch im Header!!!!
        template <class T>
        void CTest:oSomething( T & rtValue )
        {
        // Mach was mit rtValue
        }
        </pre>
        Den zweiten Fall kannst du optisch (und nur optisch!) etwas kürzen (von wegen
        elendslange Header), indem du die Funktionsdefinition(en) in eine dritte Datei auslagerst,
        die du am Ende des Headers inkludierst -- den Trick hast du ja scheinbar
        jetzt schon verwendet. AFAIR wird das übrigens auch in der MFC so gemacht --
        schau dir mal die *.inl-Files in den MFC-Sourcen an.

        <p><i>entspricht zwar keinem objektorientierten Ansatz wegen der Makros</i><br>
        Das hat doch mit OO oder nicht OO nix zu tun. Und Makros sind auch nur
        <b>potentiell</b> böse -- man muss sie halt mit Verstand einsetzen, dann sind
        sie ungemein nützlich (IMNSHO).

        <p><i>(aber was ist bei MS schon objektorientiert? die MFC - nicht
        wirklich...)</i><br>
        ACK. Aber das wäre mir eigentlich wurscht (bin ja kein Dogmatiker :-)). Was
        mich wirklich nervt, ist dass jede Popelaktion einen Riesenaufstand erfordert.
        Nachdem ich mittlerweile mit dem RAD-Virus infiziert bin (Delphi, notfalls
        auch VB), ist es eine Qual, mit class wizard und Co. ein neues Control oder
        eine neue Ereignisbehandlungsroutine zu einem Dialog hinzuzufügen. :-(

        <p><i>eigentlich ist mir unklar wie so eine einfache Sache</i><br>
        Such mal in den einschlägigen C++-Newsgroups nach Diskussionen über getrennte
        Compilierung von Templates (Schlüsselwort export). Dann wirst du feststellen,
        dass das <b>keine</b> einfache Sache ist.

        <p><i>die zB unter Linux und dem gcc compiler wunderbar funktioniert</i><br>
        Das halt ich für ein Gerücht.

        <p>Ciao, Uli

        Comment


        • #5
          mir ist bewusst, dass diese lösung mehr als kompliziert und auch eigentlich so trickreich ist, dass sie schon wieder gegen alles verstoßt (warbarkeit, lesbarkeit) und außerdem is sie getrickst...<br><br>





          noch kurz zum linux+gcc: das geht sehr wohl - ich habe da einige klassen selbst und auch andere geschrieben. funktioniert wirklich TADELLOS... deswegen meinte ich ja "einfache" sache, dort ist es nämlich eine solche :-) <br><br>





          der ganze code unter linux geschrieben soll nämlich auch jetzt auf windows portiert werden, daher ja meine frage ;-) <br><br>





          aber deine eigentlich ganz einfache variante scheint mir logisch. muss mich noch mit den anderen in verbindung setzen...





          leider kann ich mir die mfc files (noch) nicht anschauen, weil ich noch kein windows drauf hab - sollte aber in den nächsten stunden-tagen kommen, wenn die portierung startet, dieses problem ist uns allerdings jetzt schon bekannt. aber du könntest ja für mich ein "probe"-file von denen irgendwo hinstellen. wär ganz nett... (zB microsoft-newsgroup, da kann man dateien anhängen und man muss sich nicht registrieren)


          mfg


          ale

          Comment


          • #6
            Die *.inl-Variante ist keine Hexerei. Einfach einen Teil des Codes aus dem Header in eine zweite Datei auslagern:<pre>
            // Datei test.h
            class CTest
            {
            ...
            template <class T>
            void DoSomething( T & rtValue );
            }
            <br>
            // Immer noch im Header!!!!
            #include "test.inl"
            <br>
            <br>
            // =========================================
            // Datei test.inl:
            template <class T>
            void CTest:oSomething( T & rtValue )
            {
            // Mach was mit rtValue
            }
            </pre>
            Und von wegen gcc: Kannst du mal ein Minimalbsp. stricken (so etwa eine Klasse mit einer Template-Methode + eine Mainfunktion), das das Problem zeigt und sich mit dem gcc kompilieren lässt?
            <p>Uli

            Comment


            • #7
              hab grad windows aufgesetzt und visual c++ 6.0 (sp 5) gestartet. das .net kommt noch...<br>
              <br>
              dialog-mfc-projekt angelegt.<br>
              <br>
              klasse ctest hinzugefügt und das probiert was du oben geschrieben hast. einen button hinzugefügt und versucht bei dem Event die Klasse zu erzeugen und dann die die "DoSomething" Methode aufzurufen.<br>
              <br>
              Folgender Fehler:<br>
              <br>
              C:\Programme\Microsoft Visual Studio\MyProjects\probe\probeDlg.cpp(180) : error C2893: Funktionsvorlage 'void __thiscall CTest:oSomething(T)' konnte nicht spezialisiert werden
              Mit den folgenden Vorlagenargumenten:
              'int'<br><br&gt

              Comment


              • #8
                Stimmt. Ich habe grad ein Konsolenprojekt mit folgenden drei Dateien gebastelt:
                <pre>
                // TemplateTest.cpp:
                <br>
                #include "test.h"
                <br>
                int main(int argc, char* argv[])
                {
                CTest t;
                int i;
                i = 7;
                t.DoAnotherThing(i);
                t.DoAnotherThing<int>(i);
                return 0;
                }
                </pre><pre>
                // test.h:
                #ifndef __TEST_H__
                #define __TEST_H__

                class CTest
                {
                public:
                template <typename T>
                void DoSomething( T & rtValue );
                <br>
                template <typename T>
                void DoAnotherThing( T rtValue );
                };
                <br>
                #include "test.inl"
                <br>
                #endif //__TEST_H__
                </pre><pre>
                // test.inl:
                #include <iostream>
                <br>
                template <typename T>
                void CTest:oSomething( T & rtValue )
                {
                std::cout << rtValue << std::endl;
                }
                <br>
                template <typename T>
                void CTest:oAnotherThing( T rtValue )
                {
                std::cout << rtValue << std::endl;
                }
                </pre>
                Meiner Meinung nach müsste ein C++-Compiler beide Aufrufe von DoAnotherThing ohne Mäkeleien kompilieren. Mit VC++6 krieg ich aber bei jedem Aufruf eine Fehlermeldung. Ich schau später daheim mal, was der gcc dazu sagt. :-)
                <br>Uli

                Comment


                • #9
                  funktioniert leider nicht, weil angeblich laut microsoft spezifikation die template member-methoden direkt im header der klasse ausimplementiert werden müssen!

                  mfg
                  alex

                  PS: der gcc sollte es packen (ich hab gcc 2.95.x oder so benutzt...).
                  Diese Art der Implementierung über die wir hier reden ist auch eigentlich Standard und sollte eigentlich überall funktionieren - aber MS halt, naja..

                  Comment

                  Working...
                  X