templates: Fehler: error: expected initializer before ‘<’ token



  • Hallo,

    ich habe folgendes:

    Auto.h

    template<class T>
    class Auto{
    ...
    void fahre();
    
    }
    
    #include Auto.cpp
    

    und

    Auto.cpp

    template<class T> void Auto<T>::fahre(){
    
    }
    

    wenn ich das debuggen will, bekomme ich folgenden Fehler:

    error: expected initializer before ‘<’ token
    

    Kann mir jemand helfen?

    Hab ich es richtig verstanden, dass ich bei Templates die .cpp datei in die header datei einbinden muss?



  • bei Templates die .cpp datei in die header datei einbinden

    Ne, das ist genauso wie ohne Templates.
    Eine Klasse schließt man übrigens mit ";" ab.



  • wenn ich alles in die header datei packe, bekomme ich keine Probleme.
    Nur leider wird es dann zu unübersichtlich.
    Wie kann ich eine .cpp und eine .h datei haben und alles richtig zusammenfügen?



  • so wie du es gemacht hast ist es im Grunde schon richtig. Manche benennen die Implementierungs-Dateien von Templates allerdings nicht mit .cpp sondern eben anders.

    moagnus schrieb:

    bei Templates die .cpp datei in die header datei einbinden

    Ne, das ist genauso wie ohne Templates.

    Falsch. Der Compiler braucht bei Templates den kompletten Template-code, wenn sie irgendwo genannt werden. Der Grund ist, dass Klassentemplates eben keine fertigen Klassen sind und der Compiler an der entsprechenden Stelle erst den eigentlichen Klassencode generieren muss. Es gibt zwar das export-Keyword, mit dem der Compiler aus dem Templatecode so eine Art Template-Zwischencode erzeugt, allerdings wird das nur von ein oder zwei Compilern unterstützt (die gebräuchlichen MSVC und GCC gehören nicht dazu).



  • hmm nur wie kommt jetzt dieser Fehler zustande..

    der fehler tritt übrigens bei der .cpp datei auf.
    Meint er das erste "<" oder eher das zweite "<" kann ich das irgendwie sehen?

    (ich benutzte eclipse cdt unter linux)



  • ich hab noch ein zweites Beispiel gemacht.. "berühmte Stack-Beispiel"
    (kommt derselbe Fehler)

    Stack.h

    #ifndef STACK_H_
    #define STACK_H_
    #include <cassert>
    #include <iostream>
    using namespace std;
    
    template <class T> class Stack {
    
    public:
    
    	static const unsigned int MAX_SIZE =20;
    	Stack():anzahl(0){};
    	~Stack(){};
    	bool empty() const { return anzahl == 0; }
    	bool full() const { return anzahl == MAX_SIZE; }
    	unsigned int size() const { return anzahl; }
    	void clear() { anzahl=0;}
    
    	const T& top() const;
    	void pop();
    
    	void push(const T &x);
    
    	void print();
    
    private:
    	unsigned int anzahl;
    	T array[MAX_SIZE];	// Behälter für Elemente
    
    };
    
    //template<class T> const T& Stack<T>::top() const{
    //	assert(!empty());
    //	return array[anzahl-1];
    //}
    //
    //template<class T> void Stack<T>::pop(){
    //	assert(!empty());
    //	--anzahl;
    //}
    //
    //template<class T> void Stack<T>::print(){
    //	std::cout<<"HUHU ich bin da  "<<array[anzahl-1]<<std::endl;
    //}
    //
    //template<class T> void Stack<T>::push(const T &x){
    //	assert(!full());
    //	array[anzahl++] = x;
    //
    //}
    
    #include "Stack.cpp"
    
    #endif /* STACK_H_ */
    

    Stack.cpp

    #include <cassert>
    #include <iostream>
    using namespace std;
    
    template<class T> const T& Stack<T>::top() const{
    	assert(!empty());
    	return array[anzahl-1];
    }
    
    template<class T> void Stack<T>::pop(){
    	assert(!empty());
    	--anzahl;
    }
    
    template<class T> void Stack<T>::print(){
    	std::cout<<"HUHU ich bin da  "<<array[anzahl-1]<<std::endl;
    }
    
    template<class T> void Stack<T>::push(const T &x){
    	assert(!full());
    	array[anzahl++] = x;
    
    }
    

    zum generellen Verständis:
    muss ich in meiner aufrufenden Datei Stack.cpp oder Stack.h "includen"?

    Der Fehler tritt bei beiden auf 😞
    wie gesagt, wenn ich alles im Header lasse, gibt es keinen Fehler..
    Irgendjemand eine Idee?



  • Nimm keine .cpp-Dateien, üblicherweise werden die nämlich als Module kompiliert. Nimm stattdessen .inl, .impl oder .hpp als Endung.



  • laraM schrieb:

    zum generellen Verständis:
    muss ich in meiner aufrufenden Datei Stack.cpp oder Stack.h "includen"?

    Immer die .h

    laraM schrieb:

    Meint er das erste "<" oder eher das zweite "<" kann ich das irgendwie sehen?

    Einige Compiler geben nicht nur die Zeilezahl sondern auch die Spaltenzahl an, daran könnte mans sehen. Alternativ machst du irgendwo dazwischen an geeigneter Stelle einen Zeilenumbruch und kannst dann genau sehen welche von beiden es ist.

    Das using namespace solltest du übrigens normalerweise weglassen in Headern, das kann zu Problemen führen. Bei templates gilt das dementsprechend auch für die .impl-Datei, da die ja indirekt auch mit dem Header eingebunden wird. Außerdem scheibst du std::cout und std::endl ja eh schon voll qualifiziert..
    Außerdem würde ich das #include <iostream> im Header weglassen, da du es dort ja nicht benutzt..



  • Nur ums nochmal deutlich zu machen. Du kannst bei Templateklassen die Deklaration und Implementation nicht auf eine h/cpp Datei aufteilen. Das muss in einer Datei stehen.
    Was geht und was die anderen auch mit ihren Vorschlägen meinten:
    template.hpp:

    template<typename T>
    class Foo
    {
        void bar(T val);
    };
    #include template.impl//oder auch .hpp .h oder .wasauchimmer
    

    template.impl:

    template<typename T> void Foo::bar(T val)
    {
       [...]
    }
    

    So hättest du ebenfalls eine Aufteilung von Deklaration und Implementation.



  • Gate schrieb:

    template<typename T> void Foo::bar(T val)
    

    Ausserhalb des Templates muss die Klasse aber vollständig angegeben werden. Oft braucht es auch typename für abhängige Typen.

    template<typename T> void Foo<T>::bar(T val)
    

    Gate schrieb:

    #include template.impl//oder auch .hpp .h oder .wasauchimmer
    

    Und hier fehlen Anführungs- und Schlusszeichen... 😉



  • Und besser kein "using namespace" in einen Header packen, sonst gilt das unfreiwilligerweise ja auch für alle inkludierenden Module 🙂


Anmelden zum Antworten