Template spezialisierung



  • Hi zusammen

    Ich bin irgendwie immer noch an meinen template-sachen und jo.. da ist auch schon die nächste unklarheit 😞

    Wenn ich folgendes template deinier:

    template <class T>
    class MyList
    {
    private:
    	std::vector<T> m_v;
    public:
    	MyList();
    	virtual ~MyList();
    
    	void add(const T& item);
    	int count();
    	T &getItem(int index);
    };
    

    Dann kann ich dieses auf folgende Art und Weise verwenden:

    TestClass *p1 = new TestClass();
    MyList<TestClass*> vp;
    vp.add(p1);
    

    Und es funktioniert alles, wie erwartet und gewünscht.

    Jetzt will ich das Template für Pointer spezialisieren, einige funktionen erganzen und einige Sachen am Verhalten ändern. Wenn ich aber folgende spezialisierung definiere:

    template<class T> class MyList<T*> : public MyList<T>
    {
    public:
    	virtual void test2();
    };
    

    Schon wenn ich nur eine Funktion auf dem spezialisierten Template ergänze (oder auch keine, es reicht, wenn es einfach eine Spezialisierung gibt) und das Template auf die selbe Art und Weise verwende, erscheint die Melung:

    Cannot cnvet parametr 1 from "TestClas *" to "const TestClass&"

    Wenn an der stell von add die Funktion test2 auf dem Template aufrufe, funktioniert das ganze..!?

    Hat jemand eine idee, was ich falsch mache oder.. ist das mit der Template-Spezialisierung gar nicht ungbedingt so gedacht, wie ich sie einsetzt?

    Ein Dankeschön, für jede idee und Ratschlag! Dominic



  • für die template-spezialisierung musst du *alle* funktionen des templates neu definieren (eben spezialisiert). das scheinst du wohl zu wissen, denn ansonsten würdest du ja nicht versuchen, zu erben. nur erbst du ja nicht von einer MyList<T*> , sondern von einer MyList<T> . d.h. die funktionen, die du erbst, sind void add (const T &) usw. wenn du sagst, du willst das template aber für T* spezialisieren, müsstest du eine methode void add (const T *) anbieten. die lösung, die du vielleicht im kopf gehabt hattest, von MyList<T*> zu erben funktioniert natürlich nicht, da du die spezialisierung ja eben erst definierst.

    was du allerdings machen könntest, ist eine gemeinsame basisklasse für die templates einzuführen und diejenigen funktionen, die du spezialisieren willst, einfach überschreiben (wenn du privat vererbst, stellst du außerdem sicher, dass nur auf bestimmte funktionen zugegriffen werden kann). du könntest allerdings auch, wenn du nur wenige funktionen zu spezialisieren hast, mit SFINAE diese jeweils an- und ausschalten (siehe boost::enable_if/boost::disable_if).



  • hey queer_boy.. thanx for answer!

    Das Problem hab ich verstanden aber hm.. irgendwie stehe ich noch immer an 😞

    Die rudimentäre Variante wäre jetzt wohl, die spezialisierte Template-Klasse getrennt von der generellen Template-Klasse zu implementieren, ohne von einander abzuleiten. Das mit der Konsequenz, dass ich nahezu alle Methoden nochmal identisch implementiere.

    Plan B wäre dann eine Basisklasse für die generelle und die spezialisierte Template-Klasse zu implementieren. So könnten die gemeinsamen Funktionen implementiert und später spazialisiert werden. Das hört sich gut an aber für mich scheint das nicht zu funktionieren, weil es das Ziel meiner Klasse, ein Template zu kapseln. Das gibt schliesslich folgendes Problem:

    Ich will z.B. die Methode "int count() { return m_v.size() }" nicht doppelt implementieren und somit in die Basisklasse tun. Diese braucht aber den Vector "m_v". Das heisst, dass dieser auch in der Basisklasse sein müsste. Das wiederum würde bedeuten, dass die Basisklasse wiederum ein Template sein müsste. Somit habe ich das selbe Problem eine stufe tiefer verschoben 😞

    Wenn man nun sagt, dass alle Funktionen, die mit dem Vektor "m_v" zu tun haben, nicht in der Basisklasse implementiert werden dürfen, dann bin ich in meinem Fall wieder bei der rudimentären Variante und würde nahezu alle Methoden neu implementieren.

    Wenn ein Vektor statt mit Templates mit Vererbung implementiert wäre, hätte er wohl etwa diese Hierarchie:

    "BaseVector" (Implementiert die Funktionen unter Verwengung von Void Pointern oder stellt abstrakte Schnettstellen-Funktionen zu Verfügung)

    "TVector" "T*Vector"

    So könnte ich in meiner Basisklasse eine Referenze auf BaseVector halten, die Funktionen mit dieser Variable implementieren, diese aber in meinen Spezialisierungen Spezialisiert kreiren.

    Ihr seht, ich komme von Sprachen, die keine Templates kennen ( Namen werden bewusst verschwigen 😉 ) Gibt es irgendwie eine Lösung für mein Problem, ohne alle Methoden redundant zu implementieren. Oder mache ich etwas grundsätzliches falsch..?

    Grüsse, Dominic



  • bayo schrieb:

    hey queer_boy.. thanx for answer!

    Das Problem hab ich verstanden aber hm.. irgendwie stehe ich noch immer an 😞

    Die rudimentäre Variante wäre jetzt wohl, die spezialisierte Template-Klasse getrennt von der generellen Template-Klasse zu implementieren, ohne von einander abzuleiten. Das mit der Konsequenz, dass ich nahezu alle Methoden nochmal identisch implementiere.

    Plan B wäre dann eine Basisklasse für die generelle und die spezialisierte Template-Klasse zu implementieren. So könnten die gemeinsamen Funktionen implementiert und später spazialisiert werden. Das hört sich gut an aber für mich scheint das nicht zu funktionieren, weil es das Ziel meiner Klasse, ein Template zu kapseln. Das gibt schliesslich folgendes Problem:

    Ich will z.B. die Methode "int count() { return m_v.size() }" nicht doppelt implementieren und somit in die Basisklasse tun. Diese braucht aber den Vector "m_v". Das heisst, dass dieser auch in der Basisklasse sein müsste. Das wiederum würde bedeuten, dass die Basisklasse wiederum ein Template sein müsste. Somit habe ich das selbe Problem eine stufe tiefer verschoben 😞

    ja, das müsste sie. aber dafür könntest du in der spezialisation die nicht passenden methoden aus der basisklasse verdecken (also quasi "überschreiben").

    außerdem könntest du das curiously recurring template pattern einsetzen, damit die basisklasse alle funktionen der kind-klasse sieht (wenn es denn wirklich notwendig ist).

    und am ende bleibt dir immernoch die möglichkeit, statt einer vollständigen spezialisierung, SFINAE zu verwenden. (google macht schlau!)


Anmelden zum Antworten