Templates - 'Undefined reference' zu Memberfunktion



  • Hi Leute,
    Ich habe gerade angefangen, mich etwas intensiver mit C++ zu beschaeftigen und bin bei dem Versuch, eine Thread-Klasse zu schreiben, auf ein Problem mit Templates gestossen, aus dem ich mir als Newbie keinen Reim machen kann.
    Mein Code (UNIX-spezifisch, aber mein Problem hat mit Standard C++ zu tun):

    thread.h:
    
    #ifndef THREAD_H
    #define THREAD_H
    #ifndef IOSTREAM
    #define IOSTREAM
    #include <iostream>
    #endif
    
    #ifndef PTHREAD_H
    #define PTHREAD_H
    #include <pthread.h>
    #endif
    
    #ifndef CSTDIO
    #define CSTDIO
    #include <cstdio>
    #endif
    
    class thread_err {
    public:
    	thread_err(int errnum_) { errnum = errnum_; }
    	inline int get_errno(void) const { return errnum; }
    	friend std::ostream &operator<<(std::ostream &out, const thread_err &t);
    
    private:
    	int	errnum;
    };
    
    inline std::ostream &operator<<(std::ostream &out, const thread_err &t) {
    	out << std::strerror(t.get_errno());
    	return out;
    }
    
    template <class T>
    class Thread {
    public:
    	virtual void	*thread_func(T arg) = 0;
    	void			run(T arg);
    
    private:
    	static void		*start(void *instance);
    	pthread_t		thr;
    	T				*argument;
    };
    
    #endif
    
    thread.cpp:
    
    #include "thread.h"
    #include <iostream>
    #include <pthread.h>
    #include <cstring>
    
    template <class T>
    void *Thread<T>::start(void *instance) {
    	Thread <T>	*t = static_cast <Thread <T> *>(instance);
    	pthread_detach(pthread_self());
    	t->thread_func(t->argument);
    }
    
    template <class T>
    void Thread<T>::run(T arg) {
    	int	rc;
    	argument = static_cast <void *>(arg);
    	if ((rc=pthread_create(&thr, NULL, start, static_cast<void *>(this))) !=0) {
    		thread_err t(rc);
    		throw t;
    	}
    }
    
    new.cpp:
    
    #include "thread.h"
    #include <iostream>
    #include <pthread.h>
    
    class Foobar : public Thread <const char *> {
    	void *thread_func(const char *arg) {
    		std::cout << arg << std::endl;
    		return NULL;
    	}
    };
    
    int main(void) {
    	Foobar f;
    	const char	*text = "hello world";
    	try {
    		f.run(text);
    	} catch (thread_err t) {
    		std::cout << "Error: " << t;
    	}
    	pthread_exit(NULL);
    }
    

    Wenn ich die Dinger mit g++ 3.2 zu kompilieren versuche (g++32 thread.cpp new.cpp -o new -pthread), erhalte ich folgenden Fehler:

    /var/tmp/cc9xiKQZ.o: In function `main':
    /var/tmp/cc9xiKQZ.o(.text+0x32): undefined reference to `Thread<char const*>::run(char const*)'
    collect2: ld returned 1 exit status
    

    Klare Sache - Keine passende Funktion fuer den Aufruf in main() vorhanden. Warum aber? Sollte das Template-Zeugs um run() in thread.cpp nicht dafuer Sorge tragen, dass bei jeder Instanz von Thread, ganz egal welcher Typ, eine passende Member-Funktion vorhanden ist?
    Danke im Voraus.



  • template-Definitionen müssen von dort, wo sie benutzt werden, sichtbar sein. Einfach in eine andere Übersetzungseinheit auslagern (wie bei normalen Funktionen und Memberfunktionen) funktioniert nicht (bzw. nur wenn du sie exportierst, aber das kann noch fast kein Compiler).



  • Hi,

    du koenntest am Ende deiner Deklarationsfile ein

    #include "thread.cpp"
    

    machen.

    mfg
    v R



  • Hi,
    erstmal vielen Dank fuer eure Antworten! #include "thread.cpp" funktioniert wunderbar, wirft jedoch die Faustregel ``niemals .cpp-Dateien inkludieren!'' ueber den Haufen. Entgegen meinen Erwartungen erhalte ich aber keine ``multiple definition''-Fehler, wenn ich eine .cpp-Datei, die nur Template-Klassen-Member enthaelt, in mehreren Dateien einfuege. Kann man daraus schliessen, dass dies kein Kludge ist um ``export'' zu umgehen, sondern generell so akzeptiert und praktiziert wird (werden muss!)? 😉



  • Genau. Ganz gerissene nennen die Datei dann auch nicht .cpp sondern .tcc oder .impl oder .inc oder sonstwas, um die Faustregel zu umgehen 😉 😉


Anmelden zum Antworten