Template-Klasse, Template-Funktionen und friend-Deklaration



  • Supi, vielen, vielen Dank!
    Es funktioniert. Hab die ganzen U's nur wieder in T' umgewandelt, damit es konsistent ist, oder hatte das einen speziellen Grund warum die in der Deklaration der Funktionen in der Klasse U statt T genommen hast?



  • Ich hätte da jetzt noch nen kleinen anderen Wunsch. Um die verschiedenen Möglichkeiten der Funktionsdefinition aufzuzeigen würde ich gerne die print-Funktion die ein Heapsort-Argument hat als Memberfunktion schreiben, also so:

    template<typename T> void print()
    	{
        print(maxheap);
        print(sortiertes_v);
    	}
    

    und rufe die dann auf mit:

    ergebnis.print();
    

    Dann bekomme ich aber die folgenden Fehler:

    error C2783: "void Heapsort<T>::print(void)": template-Argument für "T" konnte nicht hergeleitet werden.

    error C2780: 'void Heapsort<T>::print(const std::vector<T> &)': Erwartet 1 Argumente - 0 unterstützt

    Wo liegt mein Fehler in der Definition?



  • ja wenn man T für den klassen template parameter wählt und in dieser andere template funktionen (als friends) deklariert, muss das ja nicht heissen dass die parameter gleich oder verschieden sind.

    folglich sollte man den klassen parameter T(oder auch was belibiges anderes) nennen und die funktions templates innerhalb der klasse U. ob die definitionen auch diesen parameter haben ist eig egal...



  • Jetzt hast du dort eine Template-Funktion, bei der der Compiler mangels abhängiger Typen in der Parameter-Liste nicht entscheiden kann, für welches T er die Funktion generieren soll. In der Tat ist die Funktion aber auch unabhängig von T, wie es ausschaut.
    Ein Aufruf müsste zur Zeit so aussehen:

    ergebnis.print<int>();
    


  • Also du meinst ich könnte das template... weglassen?
    Mit dem Aufruf

    ergebnis.print<char>();
    

    geht es leider auch nicht.

    Hab noch überlegt ob ich dann in die Funktion void print() const

    print<T>(maxheap);
    print<T>(sortiertes_v);
    

    schreiben muss, aber auch das geht nicht.
    Da kommt dann:
    error C2662: 'void Heapsort<T>::print<T>(const std::vector<_Ty> &)': this-Zeiger kann nicht von 'const Heapsort<T>' in 'Heapsort<T> &' konvertiert werden



  • Was bedeutet "Es geht leider nicht" genau? Was sagt der Compiler dazu?



  • Also die Funktion sieht jetzt so aus:

    template<typename T> 
       void print()
      {
        print(maxheap);
        print(sortiertes_v);
      }
    

    und der Aufruf so:

    ergebnis.print<char>();
    

    dann sagt er:

    error LNK2019: Verweis auf nicht aufgelöstes externes Symbol ""public: void __thiscall Heapsort<char>::print<char>(class std::vector<char,class std::allocator<char> > const &)" (??print@D@?print@D@?Heapsort@D@@QAEXABV?vector@DV?vector@DV?allocator@D@std@@@std@@@Z)" in Funktion ""public: void __thiscall Heapsort<char>::print<char>(void)" (??print@D@?print@D@?Heapsort@D@@QAEXXZ)".

    und

    fatal error LNK1120: 1 nicht aufgelöste externe Verweise.



  • Naja, er findet jetzt keine Implementierung der print-Funktion, die ein "const std::vector<char>&" verlangt...

    Aber wie du schon sagtest, die template-Sache ist eigentlich völlig unnötig bei dieser Funktion. Alle Funktionen in einem Klassentemplate sind schon implizit von den Template-Parametern der Klasse abhängig, das heißt, solange die Funktion nicht noch von einem anderen Typ abhängen soll, kannst du dir eine template-Methode sparen.



  • Ok, wenn ich jetzt aber schreibe

    void print()
    {
        print(maxheap);
        print(sortiertes_v);
    }
    

    sagt der Compiler mir:

    error C2780: 'void Heapsort<T>::print(const std::vector<T> &)': Erwartet 1 Argumente - 0 unterstützt

    Was muss ich denn da jetzt noch verändert, dass der Aufruf funktioniert-



  • oder noch besser wäre:

    void print() const
    {
        print(maxheap);
        print(sortiertes_v);
    }
    

    aber da kommt auch wieder

    error C2780: 'void Heapsort<T>::print(const std::vector<T> &)': Erwartet 1 Argumente - 0 unterstützt
    1> with
    1> [
    1> T=char
    1> ]



  • Kannst du bitte deinen aktuellen Quelltext nochmal ganz posten? Ich weiß ja nicht, ob du die inkorrekte definition der Methoden außerhalb der Klasse inzwischen schon gefixt hast usw.

    Und irgendwie muss ich auch mal anmerken, dass mir die ganze Klasse mit ihren friend-Funktionen da ziemlich komisch und undurchsichtig anmutet!



  • Also der komplette Quelltext, Header und cpp-Datei

    #ifndef HEAPSORT_H
    #define HEAPSORT_H
    
    #include<assert.h>
    #include<vector>
    #include<iostream>
    
    typedef unsigned int uint; 
    using namespace std;
    
    template<typename T>
    class Heapsort
    {
    
    private:
        vector<T> maxheap;
        vector<T> sortiertes_v;
    
    public:
        Heapsort(vector<T> const& v): sortiertes_v(), maxheap(v) {};
    
        template<typename T> friend void gen_maxheap(vector<T>& v);
    	template<typename T> friend void test_sinken(vector<T>& v, uint i);
        template<typename T> friend void sortieralgo(vector<T> const& v, Heapsort<T>& ergebnis);
        template<typename T> inline void tausche(T& v, T& k);
        template<typename T> inline void print(vector<T> const& v);
    	//template<typename T> friend inline void print(Heapsort<T> const& v);
    
    	void print() const
    	{
        print(maxheap);
        print(sortiertes_v);
    	}
    
    };
    
    template<typename T>
    void gen_maxheap(vector<T>&  v)
    {
        for(int i = (v.size() / 2 - 1) ; i >= 0; i--)
        {
            test_sinken( v, i);
    
        }
    }
    template<typename T>
    void test_sinken(vector<T>& v, uint i)
    {
        while(i <= v.size() / 2 - 1)
        {
            uint kindindex = 2*i + 1;            //Index des linken Kindknotens
            if(kindindex+1 <= v.size()-1)            //Rechtes Kind?
            {
                if(v[kindindex] < v[kindindex+1])
                    kindindex++;
            }
    
            if(v[i] < v[kindindex])
            {
                tausche(v[i], v[kindindex]);
                i = kindindex;
            }
            else
                break;
    
        }
    }
    
    template<typename T>
    void sortieralgo(vector<T> const& v, Heapsort<T>& ergebnis)
    {
        gen_maxheap<T>(ergebnis.maxheap);
        vector<T> w= ergebnis.maxheap;
    
        while(w.size() > 0)
        {
            tausche(w.front(), w.back());
            (ergebnis.sortiertes_v).push_back(w.back());
            w.pop_back();
            if(w.size()==1)
            {
                (ergebnis.sortiertes_v).push_back(w.back());
                w.pop_back();
            }
            else
                test_sinken(w, 0);
        }
    }
    
    template<typename T>
    void tausche(T& v, T& k)
    {
        T temp = v; 
        v = k;
        k = temp;
    };
    
    template<typename T>
    void print(vector<T> const& v)
    {
        for(uint i = 0; i < v.size(); i++)
        {
            cout << v[i] << " " ;
        }
        cout << endl;
    }
    
    //template<typename T>
    //void print(Heapsort<T> const& ergeb)
    //{
    //    print(ergeb.maxheap);
    //    print(ergeb.sortiertes_v);
    //}
    
    #endif
    
    #include<cassert>
    #include<vector>
    #include<iostream>
    #include "Heapsort_Prüfung.h"
    
    using namespace std;
    
    typedef unsigned int uint;
    
    int main()
    {
        vector<char> v;
        v.push_back('H');
        v.push_back('E');
        v.push_back('A');
        v.push_back('P');
        v.push_back('S');
        v.push_back('O');
        v.push_back('R');
        v.push_back('T');
    
        Heapsort<char> ergebnis(v);
        sortieralgo(v,ergebnis);        //Aufruf des sortieralgorithmus
        print(v);
    	ergebnis.print<char>();
    	//print(ergebnis);
        //ergebnis.print<char>();
    
    	system ("pause");
        // cin.get();
        return 0;
    }
    

    was meinst du denn mit undurchsichtig? ich hab halt für die Prüfung versucht möglichst viele Möglichkeiten, die C++ bietet in den Code zu packen, d.h. z.B das mit der friend Deklaration.

    Ich hätte die private Klassenmember auch public machen können, da wäre das um einiges einfacher und ich hätte auch keine Klasse für den ganzen Code gebraucht...so musste ich eben noch zwei Klassenmember "erfinden".



  • So hab grade gemerkt, dass der Aufruf jetzt falsch ist, aber auch wenn ich das korrigiere kommen noch Fehler:

    #include<cassert>
    #include<vector>
    #include<iostream>
    #include "Heapsort_Prüfung.h"
    
    using namespace std;
    
    typedef unsigned int uint;
    
    int main()
    {
        vector<char> v;
        v.push_back('H');
        v.push_back('E');
        v.push_back('A');
        v.push_back('P');
        v.push_back('S');
        v.push_back('O');
        v.push_back('R');
        v.push_back('T');
    
        Heapsort<char> ergebnis(v);
        sortieralgo(v,ergebnis);        //Aufruf des sortieralgorithmus
        print(v);
    	ergebnis.print();
    	//print(ergebnis);
        //ergebnis.print<char>();
    
    	system ("pause");
        // cin.get();
        return 0;
    }
    

    Fehler:

    rror C2663: 'Heapsort<T>::print': für 2 Überladung(en) gibt es keine zulässige Konvertierung für den this-Zeiger
    1> with
    1> [
    1> T=char
    1> ]

    und noch einiges mehr... 😕



  • Wofür ist die Heapsort-Klasse eigentlich gut, wenn du alles mit friend-Funktionen außerhalb der Klasse machst? Ich verstehe den ganzen Ansatz nicht, und warum deklarierst du Funktionen als friends, die gar nicht auf private-member von der Klasse zugreifen?
    Warum benutzt du inline? Warum deklarierst du Member-Funktionen und versuchst sie dann als freie Funktionen zu implementieren?
    Mir tut das im Gehirn weh, wenn ich das da vor mir sehe 😞
    Also was ich meine ist, du hast da noch viel grundlegendere Probleme als nur die Compiler-Fehler, im Moment.



  • Und vor allem: Warum ist Heapsort überhaupt eine Klasse? Wir sind hier nicht bei Java, sondern können auch freie Funktionen definieren.



  • also wäre so besser...

    #include<cassert>
    #include<vector> 
    #include<iostream>
    
    using namespace std;
    
    typedef unsigned int uint;
    
    template<typename T>						//Array vom Typ T zur Sortierung
    void gen_maxheap(vector<T>& v)
    {
    	for(int i = (v.size() / 2 - 1) ; i >= 0; i--)
    	{
    		test_sinken( v, i);
    
    	}
    }
    template<typename T>
    void test_sinken(vector<T>& v, uint i)
    {
    	while(i <= v.size() / 2 - 1)
    	{
    		uint kindindex = 2*i + 1;			//Index des linken Kindknotens
    		if(kindindex+1 <= v.size()-1)			//Rechtes Kind?
    		{
    			if(v[kindindex] < v[kindindex+1])
    				kindindex++;
    		}
    
    		if(v[i] < v[kindindex])
    		{
    			tausche(v[i], v[kindindex]);
    			i = kindindex;
    		}
    		else
    			break;
    
    	}
    }
    
    template<typename T>
    void heapsort(vector<T>& v, vector<T>& sortiertes_v)
    {
    gen_maxheap(v);
    print(v);
    	while(v.size() > 0)
    	{
    		tausche(v.front(), v.back());
    		sortiertes_v.push_back(v.back());
    		v.pop_back();
    		if(v.size()==1)
    		{
    			sortiertes_v.push_back(v.back());
    			v.pop_back();
    		}
    		else
    			test_sinken(v, 0);
    
    	}
    }
    template<typename T>
    void inline tausche(T& v, T& k)
    {
    	T temp = v;
    	v = k;
    	k = temp;
    }
    
    template<typename T>
    void inline print(vector<T> const& v)
    {
    	for(uint i = 0; i < v.size(); i++)
    		{
    			cout << v[i] << " " ;
    		}
    		cout << endl;
    }
    
    int main()
    {
    	vector<char> v;
    	v.push_back('H');
    	v.push_back('E');
    	v.push_back('A');
    	v.push_back('P');
    	v.push_back('S');
    	v.push_back('O');
    	v.push_back('R');
    	v.push_back('T');
    
    	vector<char> sortiertes_v;
    	heapsort(v, sortiertes_v);
    	print(sortiertes_v);
    
    	system ("pause");
    	return 0;
    }
    

    Ich hatte ja schon mal geschrieben, dass das ein Programm ist, was ich zur mündlichen Prüfung mitnehme. Und da habe ich versucht viele c++ Features reinzupacken, d.h. neben Template-Klasse auch Template-Funktionen, include "Header.h", freind-Deklaration um auf private member zuzugreifen usw.
    Den Code den ich jetzt hochgeladen habe der macht im Prinzip das gleiche...nur eben mit weniger Features...



  • Naja, du könntest den Sortier-Algo zB. für den Vergleich (Also die Ordnung template'isieren. Und dann nen Vergleichs-Funktor mitgeben oder sowas.

    Die Ausgabe könntest du durch überladung des << Operators implementieren. Das wäre alles "sinnvoll" und würde zusätzlich noch etwas von C++ zeigen.



  • KISS ... selbe Mächtigkeit mit weniger 'Features' ist doch gut??


Anmelden zum Antworten