Templateklasse verwenden



  • Hallo!
    Follgendes Problem.

    Ich versuche eine Hashtabelle zu programmieren. Ich bekomme eine Fehlermeldung
    error C2955: "HashElement": Für die Verwendung der template-Klasse ist eine template-Argumentliste erforderlich.

    Es ist mir schon klar dass ich sagen muss von welchem Type soll mein ListElement sein. Type ist aber variabel... Hat jem ne Idee?

    Danke schon mal.

    HashElement.h

    #ifndef __HASHELEMENT__INCLUDED__
    #define __HASHELEMENT__INCLUDED__
    
    #include <string>
    
    using namespace std;
    
    template <typename T>
    class HashElement {
    
    public:
      string    key;
      T         value;
      int		hashValue;
    
      /**
      * Konstruktor.
      */
      HashElement(string key, T value, int hashValue){
    	this->key		= key;
    	this->value		= value;
    	this->hashValue         = hashValue;
      }
    
    };
    
    #endif
    

    Hashtable.h
    Zeile 14 Fehlermedung.

    #ifndef __HASHTABLE__INCLUDED__
    #define __HASHTABLE__INCLUDED__
    
    #include <list>
    #include "HashElement.h"
    
    using namespace std;
    
    class Hashtable {
    
    private:
      /** Array mit Listen */
      list<HashElement>* table;  //HIER FEHLER!
    
      /** Laenge des Arrays */
      int size;								
    
      /**
      * Ermittelt einen Hashwert aus einem Key
      * @return hashcode
      */
      int hashcode(string key);
    
    public:
    	Hashtable(int nsize);
    	~Hashtable();
            ...
    
    };
    
    #endif
    


  • Du brauchst dort so etwas:

    list<HashElement<int> >* table;
    

    HashElement ist bei dir ja auch ein Template. Also musst du da auch einen Typen angeben.



  • Dit_ schrieb:

    error C2955: "HashElement": Für die Verwendung der template-Klasse ist eine template-Argumentliste erforderlich.

    Ist eigentlich recht eindeutig. HashElement ist selbst eine Vorlagenklasse und muss bei Verwendung mit einem Template-Argument versehen werden:

    HashElement< int >
    // --->
    std::list< HashElement< int > > ...
    

    Dit_ schrieb:

    Es ist mir schon klar dass ich sagen muss von welchem Type soll mein ListElement sein. Type ist aber variabel... Hat jem ne Idee?

    Virtuelle Basisklasse und Zeiger

    Aus einem Template werden je Argument eigenständige Klassen generiert. Mit Templates erreichst du nicht die "Variabilität", welche du dir (vielleicht) vorstellst.

    Dit_ schrieb:

    HashElement.h

    #ifndef __HASHELEMENT__INCLUDED__
    #define __HASHELEMENT__INCLUDED__
    
    #include <string>
    
    using namespace std;
    ...
    

    Zwei Dinge:

    • Keine führenden Unterstriche in Makrodefinitionen, diese sind für den Compiler reserviert.
    • Niemals using in Headerdateien verwenden. Dieses versaut dir sonst den Namensraum. In der Definition (.cpp) ist das kein Problem.

    Grüße ... Heiko



  • ja aber dann entscheide ich mich ja für einen Datentyp. table soll aus verschiedenen ListElementen-Datentypen bestehen. Sprich ich kann ListElement als double anhängen und dann sofort als int oder als meinKlass.



  • Dit_ schrieb:

    Es ist mir schon klar dass ich sagen muss von welchem Type soll mein ListElement sein. Type ist aber variabel...

    Ein statischer Typ ist in C++ niemals variabel.

    Gib bei dir an, mit welchem Templateargument du dein Klassentemplate HashElement instanziieren willst, beispielsweise:

    std::list<HashElement<int> > table; // Abstand zwischen > und >
    

    Andere Anmerkungen:

    • Was bringt der Zeiger auf std::list ? Arbeite lieber mit automatischen Objekten, sofern möglich.
    • Benutze kein using namespace in Headerdateien, da der Namensraum in allen inkludierenden Dateien so irreversibel offengelegt wird.
    • Bezeichner, die zwei Unterstriche enthalten oder mit Unterstrich und Grossbuchstaben beginnen, sind für Compiler und Implementierung reserviert. Das betrifft deine Include-Guards.
    • Verwende im Konstruktor die Initialisierungsliste.
    • Ziehe Const-Referenzen Value-Parametern vor, sofern möglich (betrifft int Hashtable::hashcode(std::string key) )
    • Halte dich an die Regel der Grossen Drei: Sobald du den Destruktor implementierst, solltest du Kopierkonstruktor und Zuweisungsoperator ebenfalls definieren. In sehr vielen Fällen ist eine spezielle Kopiersemantik jedoch unnötig.


  • ok danke für die Tipps bwbg & Nexus 🙂



  • ok nächste Frage 🙂

    Weiss nicht genau wie ich Konstruktor implementiere. Es soll eine Hashtabelle mit einer bestimmten Startgröße erstellt werden.
    Ich brauche ja ein Array dafür. Jedes Mitgleid soll eine liste vom Typ HashElement sein.

    Wie erstelle ich so ein Array richtig?

    Danke schon mal.

    #ifndef HASHTABLE
    #define HASHTABLE
    
    #include <list>
    #include "HashElement.h"
    
    template <typename T>
    class Hashtable {
    
    private:
    
      list< HashElement<T> >* table;
    
      int size;								
    
      /**
      * Ermittelt einen Hashwert aus einem Key
      * @return hashcode
      */
      int hashcode(string key){
    
           //kommt noch...
    
    	return hash;
      }
    
    public:
    	/** Konstruktor. */
    	Hashtable(int nsize){
    		this->size  = nsize;
    		this->table = new table[this->size]; // falsh oder ?
    	}
    
    	/** Destruktor. */
    	~Hashtable(){ 
    		delete[] table;
    	}
    
      /*********** PUT ***********/
      void put(string key, T value){
    	// 
      }
    
      /*********** GET ***********/
      T get(string key){
            //
    	  return NULL;
      }
    
    };
    
    #endif
    


  • Du könntest std::vector benutzen, statt eines raw arrays, das erspart dir die dynamische Speicherverwaltung und das Umkopieren beim Ändern der Tabellengrösse:

    template<typename T>
    class Hashtable
    {
    public:
       // typedefs für bessere Lesbarkeit
       typedef std::list<HashElement<T> > list_type;
       typedef std::vector<list_type>     container_type;
    
    private:
       container_type    Elements_;
    
    public:
       // reserviere 101 Elemente im Vektor
       Hashtable() : Elements_( 101 )
       {
       }
    
       ...
    
    private:
       void resize( unsigned int Size )
       {
          // Vektorgrösse setzen
          Elements_.resize( Size );
       }
    };
    


  • list< HashElement<T> >* table;
    

    Nexus schrieb:

    • Was bringt der Zeiger auf std::list ? Arbeite lieber mit automatischen Objekten, sofern möglich.
    int hashcode(string key)
    

    Nexus schrieb:

    • Ziehe Const-Referenzen Value-Parametern vor, sofern möglich (betrifft int Hashtable::hashcode(std::string key) )
    /** Konstruktor. */
        Hashtable(int nsize){
            this->size  = nsize;
            this->table = new table[this->size]; // falsh oder ?
        }
    

    Nexus schrieb:

    • Verwende im Konstruktor die Initialisierungsliste.

    Nach dem Berücksichtigen meiner Vorschläge kannst du auch mal den STL-Artikel lesen. Vielleicht wäre ein gutes Buch, das Konstruktoren und solche Grundlagen erklärt, auch nicht allzu schlecht... 😉


Anmelden zum Antworten