undefined reference to class::member



  • Hallo Experten,
    die Fehlermeldung "undefined reference to Nachricht::connect_member<Receiver>(Receiver*)" erscheint nur , wenn der Übergabeparameter an "Nachricht::connect_member" ein Template* ist. Wird eine konkrete Klasse* als Übergabeparameter deklariert (z.B. Receiver*)so erscheint diese Fehlermeldung nicht! Der Fehler hat somit einen direkten Zusammenhang mit Template* .

    Hier mein Code:

    // nachricht.h
    #ifndef NACHRICHT_H
    #define NACHRICHT_H
    
    #include <functional>
    #include "receiver.h"
    
    class Nachricht
    {
    public:
        Nachricht(std::string name);
        template <typename T>
        void connect_member(T *inst); // TUT NICHT !
        //void connect_member(Receiver *inst); //TUT !
    
        ...
    };
    
    #endif // NACHRICHT_H
    
    // nachricht.cpp
    #include "nachricht.h"
    #include "receiver.h"
    
    Nachricht::Nachricht(std::string name) : _name (name) {}
    
    template <typename T>
    void Nachricht::connect_member(T *inst) // TUT NICHT
    {
    
    }
    
    /*
    void Nachricht::connect_member(Receiver* rcv) // TUT
    {
    
    }
    */
    ...
    
    // main
    #include <iostream>
    #include "sender.h"
    #include "receiver.h"
    #include "nachricht.h"
    
    using namespace std;
    
    int main()
    {
        Sender job("Vorfahren");
        Receiver T1("#1 Transition");
    
        Nachricht* pSig = job.getNachrichtByName("running");
        cout << "Nachricht heißt :" << pSig->getName() << endl;
    
        pSig->connect_member(&T1); // Hier tritt der Fehler auf wenn in 
                                   // nachricht::connect_member(T* inst) definiert ist
    
        return 0;
    }
    

    Hier die komplete Fehlermeldung:
    debug/main.o: In function main': C:\\\_apd\\Qt\_workspace\\build-sender\_receiver2-Desktop\_Qt\_5\_9\_3\_MinGW\_32bit-Debug/../sender\_receiver2/main.cpp:19: undefined reference tovoid Nachricht::connect_member<Receiver>(Receiver*)'
    collect2.exe: error: ld returned 1 exit status

    Danke für Euren Support!


  • Mod

    Definitionen von Templates müssen bei der Instantiierung des Templates sichtbar sein, sonst wird kein konkreter Code dafür erzeugt. Das hat vor allem technische Gründe, aber muss man halt einfach akzeptieren.

    Für dich heißt das konkret eine der folgenden Möglichkeiten:

    * Du packst die Definitionen der Templates direkt in den Header, dann sind sie auf jeden Fall sichtbar, wenn sie benutzt werden. Dies ist die für dich wahrscheinlich beste Möglichkeit.

    * Das gleiche wie der erste Tipp. Aber falls der Header dadurch zu lang und unübersichtlich wird, kannst du die Definitionen auch in eine Implementierungsdatei auslagern und diese dann im Header includen. Dies ist die eine Ausnahme, wo es mal sinnvoll ist, eine Datei mit Quellcode zu includen.

    * Falls man im Voraus weiß, mit welchen Parametern ein Template instantiiert werden kann/soll/darf, kann man es bei der Definition auch explizit mit diesen Parametern instantiieren. Dann wird halt an dieser Stelle der konkrete Code dafür erzeugt und an allen anderen Stellen reicht eine Deklaration des Templates in einem Header. Dies ist eher ein ziemlicher Spezialfall, den ich der Vollständigkeit halber erwähne, er trifft wohl eher nicht auf deinen Fall hier zu.



  • Danke für die Antwort Sepp. Ich habe jedoch das Template bereits im Header definiert?

    // nachricht.h
    #ifndef NACHRICHT_H
    #define NACHRICHT_H
    
    #include "receiver.h"
    
    class Nachricht
    {
    public:
        Nachricht(std::string name);
        //Nachricht();
        template <typename T> // <-- HIER
        void connect_member(T *inst); // TUT NICHT !
    ...
    };
    #endif // NACHRICHT_H
    

    Bzw. was muß ich konkret anderst machen ?



  • Du mußt die Template-Definition in den Header packen:

    template <typename T>
    void Nachricht::connect_member(T *inst)
    {
      // ...
    }
    

    (entweder unter der Klassendefinition oder aber direkt den Code der Funktion in der Klassendefinition)



  • Sorry - ich weiß nicht genau wie ich's implementieren soll.
    So etwa:

    //nachricht.h
    class Nachricht
    {
    public:
        Nachricht(std::string name);
    
        template <typename T
        void connect_member(T *inst); // TUT NICHT !
    
        template <Receiver* myType> // so irgendwie - tut jedoch nicht !
        void connect_member (myType);
    };
    

    Geht so nicht - aber wie sonst?



  • Keine nachricht.cpp. Nur nachricht.h.



  • Naja, "keine Nachricht.cpp" stimmt hier auch nicht, nur die Template-Funktion muß in den Header, die restlichen Funktionen in die "Nachricht.cpp" (wegen der ODR).

    @schnebe: Was ist so kompliziert daran? Hier nochmal komplett

    //nachricht.h
    class Nachricht
    {
    public:
        Nachricht(std::string name);
    
        template <typename T>
        void connect_member(T *inst)
        {
          // hier die Funktionsdefinition hinschreiben
        }
    };
    

    Die restlichen (non-template) Funktionen bleiben in der "Nachricht.cpp".

    PS: Warum nimmst du einen Zeiger, und keine (const) Referenz beim Parameter inst?

    Und wie sieht denn die Funktionsdefinition von connect_member aus, so daß nur diese Funktion ein Template darstellt, aber die ganze Klasse Nachricht nicht. Wenn die ganze Klasse ein Template sein soll/muß, dann hat 'manni66' doch Recht und es werden alle Template-Funktionen in den Header geschrieben (so daß es keine ".cpp" gibt).



  • ook ich habs verstanden und umgesetzt ohne Fehlermeldungen.

    Könnt ihr mir nochmal erklären warum das ganze in den Header verlegt werden muß?


Log in to reply