static + template + singleton: Wie kann man des machen?
-
Folgender Problem:
Ich hab eine Klasse. Die soll eine Funktion haben, worüber sie eine statische Instanz von sich selbst zurück gibt. Diese Klasse soll man aber auch ableiten können und dann soll Basisklasse aber bei der Funktion einen Typ von der Abgeleiteten Klasse zurück geben:template<typename _Type> inline static foo* instance() { static std::auto_ptr<foo> _inst(new _Type); return _inst.get(); }Das das so nicht geht ... ist klar
Die Instanz ist nicht einmalig, was aber gegeben sein muss. Dann kommt noch hinzu, dass ich beim ersten Aufruf, d.h. wenn die static-Variable belegt wird, einen Parameter übergeben muss:template<typename _Type> inline static foo* instance(bar const& param1) { static std::auto_ptr<foo> _inst(new _Type(param1)); return _inst.get(); }Hat da jemand eine Idee wie man das realisieren könnte?

-
Was soll bei dir "foo" sein - die Singleton-Klasse?
Aber eigentlich hast du es schon fast richtig:
template<typename Type> class Singleton { static Type* instance() { static std::auto_ptr<Type> _inst(new Type); return _inst.get(); } };Die abgeleitete Klasse erzeugst du dann einfach so:
class Test : public Singleton<Test> { };Und einen Parameter würde ich an dieser Stelle nicht übergeben, weil dann müßtest du den ja überall beim Zugriff angeben.
Du solltest dann lieber im Default-Konstruktor der abgeleiteten Klasse auf einen Parameter zugreifen, den du halt z.B. als statischen Member bereitstellst.class Test : public Singleton<Test> { static int m_initparam; public: static int SetInitParam(int param) { m_initparam = param; } Test() { // use m_initparam } };
-
Hmm ja das Problem ist jetzt aber, dass ich auch will, dass ich jetzt hingehen kann, nachdem ich einmal die FUnktion aufgerufen habe und der Typ gesetzt ist, ich die Funktion aufrufen kann (mit foo als Type) und der mir dennoch die richtige Instanz zurück gibt.
-
Hi (D)Evil,
ich bin mir nicht ganz sicher, was das soll. Wozu z.B. der Auto-Ptr? Wozu das Template (das sollte eher ein Klassen-Template, kein Funktionstemplate sein, oder)?
Das einzige Problem ist die Parameter-Initialisierung. Hierzu musst Du dann doch einen Auto-Ptr verwenden und delayed intialization verwenden, in Verbindung mit der Init-Funktion von Th.
-
Hallo nochmal,
ich fand das ganz interessant, deswegen habe ich mal was ausprobiert. Klappt eigentlich genauso, wie ich mir das dachte. Hast Du das so gemeint?
#include <memory> #include <iostream> template <typename D> struct custom_singleton { static D* instance() { return m__instance.get(); } protected: custom_singleton() { } custom_singleton(custom_singleton const&); custom_singleton& operator =(custom_singleton const&); static void init(D* inst) { m__instance = static_cast< std::auto_ptr<D> >(inst); } private: static std::auto_ptr<D> m__instance; }; template <typename D> std::auto_ptr<D> custom_singleton<D>::m__instance; struct derived : public custom_singleton<derived> { static void init(int var) { custom_singleton<derived>::init(new derived(var)); } void print() const { std::cout << "derived.m_var: " << m_var << std::endl; } private: derived(int var) : m_var(var) { } int m_var; }; int main() { derived::init(42); derived* d = derived::instance(); std::cout << "Address of d: " << d << std::endl; d->print(); }Wobei ich eine Referenz als Rückgabewert schon besser fände als einen Zeiger.
-
Hmm ja das Problem ist jetzt aber, dass ich auch will, dass ich jetzt hingehen kann, nachdem ich einmal die Funktion aufgerufen habe und der Typ gesetzt ist, ich die Funktion aufrufen kann (mit foo als Type) und der mir dennoch die richtige Instanz zurück gibt. Aber stimmt so nicht, würd was anderes auskommen.
-
(D)Evil LOGGED OUT! schrieb:
Hmm ja das Problem ist jetzt aber, dass ich auch will, dass ich jetzt hingehen kann, nachdem ich einmal die Funktion aufgerufen habe und der Typ gesetzt ist, ich die Funktion aufrufen kann (mit foo als Type) und der mir dennoch die richtige Instanz zurück gibt. Aber stimmt so nicht, würd was anderes auskommen.
Hm, das verstehe ich jetzt nicht. Die Funktion ist ja jetzt gar kein Template mehr, Du kannst natürlich aber mehrere Klassen ableiten und das ganze z.B. auch für den Typ 'foo' tun:
struct foo : custom_singleton<foo> { using custom_singleton<foo>::init; }; // … foo::init(new foo()); foo::instance(); // Oder, genauso: custom_singleton<foo>::instance();
-
Hmm war ja auch jemand anders, der das geschrieben hat. Hab im Moment noch keine Zeit es zu testen, aber schon einmal vielen dank Konrad!