c++ sich gegenseitig verwendende Templates

Kamikaze

Warrior of Sunlight
Teammitglied
Ich habe da 2 Templates die sich gegenseitig verwenden. Leider klappt das ganze nicht. Hat jemand eine Idee wo der Fehler liegen könnte?

State.h:
Code:
#ifndef STATE_H_
#define STATE_H_

#include "../list/List.h"
#include "Transition.h"

template <class AcceptTokenType> class State {
	private:
	AcceptTokenType * acceptToken;
	List<Transtion<AcceptTokenType> > * transitions;	
	public:
	State(AcceptTokenType * acceptToken);
	virtual ~State();
};

#endif /*STATE_H_*/

Transition.h:
Code:
#ifndef TRANSITION_H_
#define TRANSITION_H_

#include "State.h"

template <class StateType> class Transition {
	private:
	State<StateType> * targetState;
	
	public:
	Transition();
	virtual ~Transition();
};

#endif /*TRANSITION_H_*/

Ausgabe:
Code:
**** Build of configuration Debug for project sysprog1 ****

gmake -k all 
Building file: ../src/fsm/State.cpp
Invoking: GCC C++ Compiler
g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/fsm/State.d" -MT"src/fsm/State.d" -o"src/fsm/State.o" "../src/fsm/State.cpp"
In file included from ../src/fsm/State.h:5,
                 from ../src/fsm/State.cpp:1:
../src/fsm/Transition.h:8: error: ISO C++ forbids declaration of `State' with no type
../src/fsm/Transition.h:8: error: expected `;' before '<' token
In file included from ../src/fsm/State.cpp:1:
../src/fsm/State.h:10: error: `Transtion' was not declared in this scope
../src/fsm/State.h:10: error: template argument 1 is invalid
../src/fsm/State.h:10: error: expected unqualified-id before '>' token
gmake: *** [src/fsm/State.o] Error 1
Building file: ../src/fsm/Transition.cpp
Invoking: GCC C++ Compiler
g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/fsm/Transition.d" -MT"src/fsm/Transition.d" -o"src/fsm/Transition.o" "../src/fsm/Transition.cpp"
In file included from ../src/fsm/Transition.h:4,
                 from ../src/fsm/Transition.cpp:1:
../src/fsm/State.h:10: error: `Transtion' was not declared in this scope
../src/fsm/State.h:10: error: template argument 1 is invalid
../src/fsm/State.h:10: error: expected unqualified-id before '>' token
gmake: *** [src/fsm/Transition.o] Error 1
gmake: Target `all' not remade because of errors.
Build complete for project sysprog1

Ich benutze übrigens eclipse-cdt, falls das irgendeinen Unterschied macht.
 
Vielen Dank, auf die Sache mit der Vorwärtsdeklaration wäre ich nie gekommen. Ich bin eben von Java verwöhnt.

Für's Protokoll, ich musste in beiden Templates eine Vorwärtsdeklaration einfügen.

State.h
Code:
template <class StateType> class Transition;
Transition.h
Code:
template <class AcceptTokenType> class State;
 
Zirkuläre abhängigkeiten sind aber ein Zeichen von schlechtem Design... Überleg mal ob du evtl nicht etwas anders machen kannst.

auf bald
oenone
 
Noch ein Problem

Wieso schlechtes Design? Das ist ein Baum es gibt Knoten und Pfade, die Knoten müssen Pfade kennen und die Pfade Knoten. Was soll daran falsch sein?

Edit:
Leider habe ich noch ein Problem. Die Verwendung vom Template List im obigen Beispiel funktioniert Prima.

State.cpp
Code:
#include "State.h"

template <class AcceptTokenType>
State<AcceptTokenType>::State(AcceptTokenType * acceptToken) {
	this->transitions = new List<Transition<AcceptTokenType> >();
	this->accpetToken = acceptToken;
}

template <class AcceptTokenType> State<AcceptTokenType>::~State() {
	delete this->transitions;
}

Bei einem sehr ähnlichen Fall behauptet der Compiler List nicht zu kenne, obwohl es im Header nicht angekreidet wird.

Tokenizer.h
Code:
#ifndef TOKENIZER_H_
#define TOKENIZER_H_

#include "../fileStream/FileStream.h"
#include "../list/List.h"
#include "TokenType.h"
#include "Token.h"

class Tokenizer {
	private:
	FileStream * file;
	List<TokenType> * types;
	List<Token> * tokens;
	
	public:
	Tokenizer(FileStream * file);
	virtual ~Tokenizer();
};

#endif /*TOKENIZER_H_*/

Tokenizer.cpp
Code:
#include "Tokenizer.h"

Tokenizer::Tokenizer(FileStream * file) {
	this->file = file;
	this->types = new List<TokenType>();
	this->tokens = new List<Token>();
}

Tokenizer::~Tokenizer() {
	delete this->types;
	delete this->tokens;
}

Hier ist noch die Ausgabe aus der Console.
Code:
**** Build of configuration Debug for project sysprog1 ****

gmake -k all 
Building file: ../test.cpp
Invoking: GCC C++ Compiler
g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"test.d" -MT"test.d" -o"test.o" "../test.cpp"
Finished building: ../test.cpp
 
Building target: sysprog1
Invoking: GCC C++ Linker
g++  -o"sysprog1"  ./test.o  ./src/token/Token.o ./src/token/TokenType.o ./src/token/Tokenizer.o  ./src/list/List.o ./src/list/ListItem.o  ./src/fsm/State.o ./src/fsm/Transition.o  ./src/fileStream/FileStream.o   
./src/token/Tokenizer.o(.text+0x132): In function `Tokenizer::Tokenizer(FileStream*)':
../src/token/Tokenizer.cpp:5: undefined reference to `List<TokenType>::List()'
./src/token/Tokenizer.o(.text+0x183):../src/token/Tokenizer.cpp:6: undefined reference to `List<Token>::List()'
./src/token/Tokenizer.o(.text+0x1f2): In function `Tokenizer::Tokenizer(FileStream*)':
../src/token/Tokenizer.cpp:5: undefined reference to `List<TokenType>::List()'
./src/token/Tokenizer.o(.text+0x243):../src/token/Tokenizer.cpp:6: undefined reference to `List<Token>::List()'
gmake: *** [sysprog1] Error 1
gmake: Target `all' not remade because of errors.
Build complete for project sysprog1

Ich wäre für Hilfe sehr dankbar. Ich stehe mal wieder total auf dem Schlauch.
 
Zuletzt bearbeitet:
Hallo Kamikaze,
ich vermisse in Deinem Build-Log das Bauen der List-Objekte.

>**** Build of configuration Debug for project sysprog1 ****
>
>gmake -k all
>Building file: ../test.cpp
>Invoking: GCC C++ Compiler
>g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"test.d" -MT"test.d" -o"test.o" "../test.cpp"
>Finished building: ../test.cpp

Es wird weiter unten zwar ein List-Objekt hinzugelinkt, dieses muss aber nicht zwangsläufig von erwarteten Typ sein.

Hast Du es evtl. schon einmal mit einem kompletten Rebuild versucht?

Sollte auch ein Rebuild nicht weiter helfen, kannst Du ja mal Dein Makefile hier reinstellen.

Gruß,
Karsten
 
Das hat sich inzwischen erledigt. Wenn man Templates verwendet muss man ein include für Header und Sourcen machen. Dann geht es.
Das Makefile wird übrigens von der IDE erzeugt.
 
Zuletzt bearbeitet:
Pfade kann man auch in Knoten als Hashtable/Liste definieren, mit dem Index des kindknotens, da hätte man nix zirkuläres, und zirkulär *ist* schlechtes Design, das wird einem jeder SoftwareTechnikProfessor sagen..
aber ne bessere möglichkeit als meine fällt mir aus dem stand leider auch nicht ein.
 
Sowas hat mir noch keiner Software-Technik Professor gesagt. Wenn man ein Netzwerk hat dann hat man eben Knoten und Pfade. Warum soll man die nicht als solche implementieren? Das Problem war hier einzig und allein der Determinismus von C++ der den Einsatz von Prototypen notwendig macht. An meinem Design ist nichts falsch.
 
Zurück
Oben