Von Template ableiten



  • Ich habe zweierlei Klassen, beide Templates, wobei die zweite von der ersten abgeleitet ist:

    #ifndef TREENODEBASE_H
    #define TREENODEBASE_H
    
    #include "array.h"
    
    template<class T>
    class TreeNodeBase
    {
    	public:
    		TreeNodeBase(const TreeNodeBase<T> * const parent);
    		virtual ~TreeNodeBase();
    
    	public:
    		virtual void appendLeave(const T &object);
    		virtual Array<T> getAllLeaves() const;
    		virtual const Array<T>& getAllDirectLeaves() const;
    		virtual bool containsLeave(const T &object) const;
    
    	protected:
    		Array<TreeNodeBase<T>*> m_nodes;
    		Array<T> m_leaves;
    		const TreeNodeBase<T> * const m_parent;
    };
    
    #include "treenodebase.cpp"
    
    #endif
    
    #ifndef TREENAMEDNODE_H
    #define TREENAMEDNODE_H
    
    #include "beenstring.h"
    #include "treenodebase.h"
    
    template<class T>
    class TreeNamedNode :
    		public TreeNodeBase<T>
    {
    	public:
    		TreeNamedNode();
    		TreeNamedNode(const TreeNodeBase<T> * const parent, const String &name);
    
    		virtual TreeNamedNode<T> * const appendNode(const String &name);
    		virtual SearchResult<TreeNamedNode<T>*> getNode(const String &name);
    		const String& getName() const;
    		Array<String> getAllNamesOfDirectNodes() const;
    		bool isTagAlreadyDirectChild(const String &name) const;
    
    	protected:
    		virtual TreeNamedNode<T> * createSubNode(const String &name) const;
    
    	private:
    		String m_name;
    };
    
    #include "treenamednode.cpp"
    
    #endif
    

    Ich bekomme dabei immer folgende Meldung vom Compiler (gcc 4.5.3):

    ../../../base/containers/include/treenamednode.h:9:22: error: expected template-name before '<' token
    ../../../base/containers/include/treenamednode.h:9:22: error: expected '{' before '<' token
    ../../../base/containers/include/treenamednode.h:9:22: error: expected unqualified-id before '<' token
    

    Wenn ich, testweise, den Code wie folgend ändere, dann kompiiliert es soweit, als später die halbe Funktionen der Basisklasse fehlen. Aber das ursprüngliche Problem stellt sich nicht mehr:

    #ifndef TREENAMEDNODE_H
    #define TREENAMEDNODE_H
    
    #include "beenstring.h"
    //#include "treenodebase.h"
    
    template<class T>
    class TreeNodeBase
    { };
    
    template<class T>
    class TreeNamedNode :
    		public TreeNodeBase<T>
    {
    	public:
    		TreeNamedNode();
    		TreeNamedNode(const TreeNodeBase<T> * const parent, const String &name);
    
    		virtual TreeNamedNode<T> * const appendNode(const String &name);
    		virtual SearchResult<TreeNamedNode<T>*> getNode(const String &name);
    		const String& getName() const;
    		Array<String> getAllNamesOfDirectNodes() const;
    		bool isTagAlreadyDirectChild(const String &name) const;
    
    	protected:
    		virtual TreeNamedNode<T> * createSubNode(const String &name) const;
    
    	private:
    		String m_name;
    };
    
    #include "treenamednode.cpp"
    
    #endif
    

    Falls es hilft kommen hier noch die Implementierungen:

    #include "treenodebase.h"
    
    template<class T>
    TreeNodeBase<T>::TreeNodeBase(const TreeNodeBase<T> *const parent) :
    		m_parent(parent)
    { }
    
    template<class T>
    TreeNodeBase<T>::~TreeNodeBase()
    {
    	for (ConstIterator<TreeNodeBase<T>*> iterator(m_nodes.getConstIterator()); iterator.isValid(); iterator.increment())
    		delete *iterator;
    }
    
    template<class T>
    void TreeNodeBase<T>::appendLeave(const T &object)
    {
    	m_leaves.append(object);
    }
    
    template<class T>
    Array<T> TreeNodeBase<T>::getAllLeaves() const
    {
    	Array<T> leaves;
    
    	for (ConstIterator<T> iterator(m_leaves.getConstIterator()); iterator.isValid(); iterator.increment())
    		leaves.append(*iterator);
    
    	for (ConstIterator<TreeNodeBase<T>*> iterator(m_nodes.getConstIterator()); iterator.isValid(); iterator.increment())
    		leaves.append((*iterator)->getAllLeaves());
    
    	return leaves;
    }
    
    template<class T>
    const Array<T>& TreeNodeBase<T>::getAllDirectLeaves() const
    {
    	return m_leaves;
    }
    
    template<class T>
    bool TreeNodeBase<T>::containsLeave(const T &object) const
    {
    	if (m_leaves.contains(object))
    		return true;
    
    	for (ConstIterator<TreeNodeBase<T>*> iterator(m_nodes.getConstIterator()); iterator.isValid(); iterator.increment())
    		if ((*iterator)->containsLeave(object))
    			return true;
    
    	return false;
    }
    
    #include "treenamednode.h"
    
    template<class T>
    TreeNamedNode<T>::TreeNamedNode() :
        TreeNodeBase<T>(0)
    { }
    
    template<class T>
    TreeNamedNode<T>::TreeNamedNode(const TreeNodeBase<T> *const parent, const String &name) :
    	TreeNodeBase<T>(parent),
    	m_name(name)
    { }
    
    template<class T>
    TreeNamedNode<T>* const TreeNamedNode<T>::appendNode(const String &name)
    {
    	TreeNamedNode<T>* node = createSubNode(name);
    
    	TreeNodeBase<T>::m_nodes.append(node);
    
    	return node;
    }
    
    template<class T>
    TreeNamedNode<T>* TreeNamedNode<T>::createSubNode(const String &name) const
    {
    	return new TreeNamedNode<T>(this, name);
    }
    
    template<class T>
    SearchResult<TreeNamedNode<T>*> TreeNamedNode<T>::getNode(const String &name) 
    {
    	if (m_name == name)
    		return this;
    
    	SearchResult<TreeNamedNode<T>*> result;
    
    	for (Iterator<TreeNodeBase<T>*> iterator(TreeNodeBase<T>::m_nodes.getIterator()); iterator.isValid(); iterator.increment())
    	{
    		TreeNamedNode<T> *node = dynamic_cast<TreeNamedNode<T>*>(*iterator);
    
    		result = node->getNode(name);
    
    		if (!result.hasFailed())
    			return result;
    	}
    
    	return SearchResult<TreeNamedNode<T>*>();
    }
    
    template<class T>
    const String& TreeNamedNode<T>::getName() const
    {
    	return m_name;
    }
    
    template<class T>
    Array<String> TreeNamedNode<T>::getAllNamesOfDirectNodes() const
    {
    	Array<String> names;
    
    	for (ConstIterator<TreeNodeBase<T>*> i(TreeNodeBase<T>::m_nodes.getConstIterator()); i.isValid(); i.increment())
    	{
    		TreeNamedNode<T> *node = dynamic_cast<TreeNamedNode<T>*>(*i);
    
    		assert(node != 0);
    
    		names.append(node->getName());
    	}
    
    	return names;
    }
    
    template<class T>
    bool TreeNamedNode<T>::isTagAlreadyDirectChild(const String &name) const
    {
    	for (ConstIterator<TreeNodeBase<T>*> i(TreeNodeBase<T>::m_nodes.getConstIterator()); i.isValid(); i.increment())
    	{
    		TreeNamedNode<T> *node = dynamic_cast<TreeNamedNode<T>*>(*i);
    
    		assert(node != 0);
    
    		if (name == node->getName())
    			return true;
    	}
    
    	return false;
    }
    

    Wäre toll, wenn da jemand weiter wüsste. Ich stehe wohl ziemlich auf dem Schlauch.

    mfg benediktibk

    PS: Gibts Spoiler? Wurde irgendwie recht lange ...



  • Komisch, bei mir (VC2010) baut das Beispiel:

    // tessst.cpp : Defines the entry point for the console application.
    //
    
    template <class T> class Array;
    template <class T> class SearchResult;
    class String;
    
    template<class T>
    class TreeNodeBase
    {
        public:
            TreeNodeBase(const TreeNodeBase<T> * const parent);
            virtual ~TreeNodeBase();
    
        public:
            virtual void appendLeave(const T &object);
            virtual Array<T> getAllLeaves() const;
            virtual const Array<T>& getAllDirectLeaves() const;
            virtual bool containsLeave(const T &object) const;
    
        protected:
            Array<TreeNodeBase<T>*> m_nodes;
            Array<T> m_leaves;
            const TreeNodeBase<T> * const m_parent;
    };
    
    template<class T>
    class TreeNamedNode : public TreeNodeBase<T>
    {
        public:
            TreeNamedNode();
            TreeNamedNode(const TreeNodeBase<T> * const parent, const String &name);
    
            virtual TreeNamedNode<T> * const appendNode(const String &name);
            virtual SearchResult<TreeNamedNode<T>*> getNode(const String &name);
            const String& getName() const;
            Array<String> getAllNamesOfDirectNodes() const;
            bool isTagAlreadyDirectChild(const String &name) const;
    
        protected:
            virtual TreeNamedNode<T> * createSubNode(const String &name) const;
    
        private:
            String m_name;
    }; 
    
    int main(int argc, char* argv[])
    {
    	return 0;
    }
    

    Ich meine aber, dass der Fehler etwas mit einem vergessenen 'typename' zu tun hat

    Gruss, Gast



  • Ich sehs zwar grade nicht, ob und wie das der Grund sein könnte, aber du hast da einen zirkulären #include - treenodebase.hpp/.cpp includieren sich gegenseitig. Normalerweise includiert in so einem Fall der template Header die methodendefinitionen, allerdings haben die Definitionsdateien dann andere Endungen.



  • pumuckl schrieb:

    Ich sehs zwar grade nicht, ob und wie das der Grund sein könnte, aber du hast da einen zirkulären #include - treenodebase.hpp/.cpp includieren sich gegenseitig. Normalerweise includiert in so einem Fall der template Header die methodendefinitionen, allerdings haben die Definitionsdateien dann andere Endungen.

    Die beiden includes sind Absicht, durch den Include-Guard wird sowieso nur einmal der Header inkludiert und so habe ich zudem Code-Vervollständigung und Syntax-Highlighting in der cpp. Der Fehler beim Kompilieren kommt immer noch, wenn ich den include des Headers in der cpp lösche.

    Gast_0025 schrieb:

    Ich meine aber, dass der Fehler etwas mit einem vergessenen 'typename' zu tun hat

    Wo könnte da ein typename fehlen?

    Danke für die raschen Antworten,
    benediktibk



  • Zeig uns mal bitte aufs Wesentliche reduzierten Code, bei dem das Problem noch nachstellbar ist. Das heißt, nimm alle Methoden etc. aus den Klassen nacheinander raus und schau, ob das Problem immernoch besteht.



  • Der letzte Tipp war gut, wenn auch indirekt. Der Grund des Fehlers waren zwei Include-Guards mit dem selben Namen. Ich hatte vor kurzem ein paar Sachen aufgeräumt und umbenannt, daher kommt der Konflikt wohl.

    Vielen Dank,
    benediktibk


Log in to reply