template Metode in einer template Klasse



  • Ich möchte sowas wie einen Signalhandler schreiben. Also im Prinzip: Klasse Menü ist ein Element der Klasse Fenster, Klasse Menü legt ein Signal an und Klasse Fenster übergibt dem Handler die Methode, die bei dem entsprechenden Signal aufgerufen werden soll. Mein Ansatz ist erst einmal so:

    template<class T>
    class SignalHandler
    {
      public:
        SignalHandler() {}
        ~SignalHandler() {}
    
        template<class U>
        void  connect(U* pObj, void (U::*pFunc)()) {}
    };
    

    Nun müsste sich der Handler die Zeiger merken um die Funktion später aufrufen zu können. Hier komme ich nicht so richtig weiter. Wenn ich U* Object; einfüge kommt natürlich der Fehler "declaration of ‘U’ with no type".
    Die suche mit google hat mir nicht wirklich weiter geholfen, vielleicht auch falsche Suchbegriffe. Vielleicht weiß ja jemand, wie ich dies lösen kann oder es gibt irgendwo ähnlichen Code.
    Gruß Steffan



  • Hallo stefkowa,

    also generell hat dein Problem nichts damit zu tun, dass deine Klasse eine Template-Klasse ist. Es ist in jeder anderen Klasse das gleiche Problem.

    Du kannst es generell etwa so lösen:

    #include <iostream>
    #include <vector>
    
    struct Function{
    	virtual void func() = 0;
    	virtual ~Function(){}
    };
    
    template<typename T>
    struct FunctionImpl : public Function{
    	FunctionImpl(T* pObj, void (T::*pFunc)()) : pObj(pObj), pFunc(pFunc) {}
    
    	virtual void func(){
    		(pObj->*pFunc)();
    	}
    
    	T* pObj;
    	void (T::*pFunc)();
    };
    
    class FooBar{
    public:
    
    	template<class T>
    	void add(T* pObj, void (T::*pFunc)()){
    		list.push_back(new FunctionImpl<T>(pObj, pFunc)); // Im Destruktor wieder löschen!!!
    	}
    
    	void foobar(){
    		for(std::vector<Function*>::iterator it = list.begin(); it!=list.end(); ++it){
    			(*it)->func();
    		}
    	}
    
    private:
    	std::vector<Function*> list;
    };
    
    struct Foo{
    	void foo(){
    		std::cout << "foo()" << std::endl;
    	}
    };
    
    struct Bar{
    	void bar(){
    		std::cout << "bar()" << std::endl;
    	}
    };
    
    int main(){ 
    	FooBar fooBar;
    	Foo foo;
    	Bar bar;
    	fooBar.add(&foo, &Foo::foo);
    	fooBar.add(&bar, &Bar::bar);
    	fooBar.foobar();
    }
    

    Also eine Basis-Klasse mit vitueller Funktion und dann instanziierst du eine Template-Klasse, die diese implementiert.

    Wenn du allerdings bereits vorhandene Mechanismen nutzen willst kann ich
    dir zu std::function in C++0x raten bzw. zu der Implementierung von boost, falls
    du kein C++0x verwendest. Das nimmt dir jede Menge Arbeit ab.
    Ich würde dir also zu etwas wie folgendem Code raten:

    #include <iostream>
    #include <functional>
    #include <vector>
    
    class FooBar{
    public:
    	typedef std::function<void()> function_type;
    
    	void operator+=(function_type func){
    		list.push_back(func);
    	}
    
    	void operator()(){
    		for(function_type& func : list){
    			func();
    		}
    	}
    
    private:
    	std::vector<function_type> list;
    };
    
    struct Foo{
    	void foo(){
    		std::cout << "foo()" << std::endl;
    	}
    };
    
    struct Bar{
    	void bar(){
    		std::cout << "bar()" << std::endl;
    	}
    };
    
    int main(){ 
    	FooBar fooBar;
    	Foo foo;
    	Bar bar;
    	fooBar += std::bind(&Foo::foo, std::ref(foo));
    	fooBar += std::bind(&Bar::bar, std::ref(bar));
    	fooBar();
    }
    

    Gruß,
    XSpille



  • Schöner Beitrag! 👍 😋



  • volkard schrieb:

    Schöner Beitrag! 👍 😋

    Danke!!! Ich fühle mich geehrt 🙂



  • edit: egal. Ich schau mir XSpilles Lösung erstmal genauer an, bevor ich eventuell dumme Fragen stelle 😛



  • Ich verstehe volkard nicht.



  • 314159265358979 schrieb:

    Ich verstehe volkard nicht.

    Ich Dich auch nicht.

    Ich denke, XSpille hat mit dem Code stefkowa mehr gegeben als es nur ein flapsigen Hinweis, wie man es machen sollte, schaffen könnte. stefkowa kapiert, wie es geht. Die konkrete Lösung halte ich für irrelevant. Er zeigt, wie es generell geht (und schreibt das sogar drüber). Ich denke, das ist hier supi angemessen als erstes Posting.

    Dein Job wäre jetzt, das noch durch einen Link wie http://www.highscore.de/cpp/boost/ereignisbehandlung.html zu ergänzen.
    Nach Möglichkeit mit "Das da wäre auch echt eine Überlegung wert." statt "Alles Scheiße! Mach so!".



  • Ich hab nie gesagt dass sein Post schlecht wäre. Nur, dass ich dich nicht verstehe.



  • @stefkowa:
    Ich frage mich gerade, was der Templateparameter T für eine Funktion hat. Der wird ja nirgens verwendet.

    Geht es Dir darum, std::bind und std::function bzw (boost::*) zu verstehen und nachzuprogrammieren, oder kennst du das noch nicht? Es wäre nämlich damit sehr einfach.

    struct foo {
      void bar();
    };
    
    int main() {
      foo o;
      function<void()> f = bind(&foo::bar,&o);
      f();
    }
    

    (ungetestet)



  • 314159265358979 schrieb:

    Ich hab nie gesagt dass sein Post schlecht wäre. Nur, dass ich dich nicht verstehe.

    Hast du heute wieder zu viele überzuckerte Cornflakes gegessen, oder ...? 🙄



  • Ich habe seit 3 Tagen nichts mehr gegessen.



  • 314159265358979 schrieb:

    Ich habe seit 3 Tagen nichts mehr gegessen.

    Ah, natürlich. Du musst auf deine Figur achten. 😃



  • @XSpille und @krümelkacker: std::function kannte ich noch nicht und scheint genau das zu sein, was ich haben möchte. Wollte auch gleich mal das zweite Beispiel von XSpille bei mir umsetzen, bekomme aber bei

    typedef std::function<void()> function_type;
    

    die Fehlermeldung "declaration of ‘function’ with no type". <functional> wird eingebunden. Ich habe den GNU GCC Compiler 4.4.5. Wird das da noch nicht unterstüzt oder fehlt noch eine Angabe?

    @krümelkacker: Nach nochmaliger Betrachtung, hast recht, die Klasse bräuchte im meinen Versuchsansatz kein Template sein.



  • Hallo stefkowa,

    hast du beim Kompilieren -std=c++0x mit übergeben?
    Also wenn ich es nicht mache, bekomme ich zwar eine andere Fehlermeldung, aber
    woran es sonst liegt, weiß ich nicht.

    In 4.4.5 musst du, falls du mein Beispiel kompilieren willst, noch
    auf die alt bekannte weise iterieren:

    void operator()(){
    		for(std::vector<function_type>::iterator it = list.begin(); it!=list.end(); ++it){
    			(*it)();
    		}
    	}
    

    g++ test.cpp -O3 -std=c++0x -o test

    Also mit g++-mp-4.4 (GCC) 4.4.5 funktioniert es bei mir auf dem Mac.

    Gruß,
    XSpille



  • Mit -std=c++0x funktioniert es.

    Danke



  • 314159265358979 schrieb:

    Ich habe seit 3 Tagen nichts mehr gegessen.

    Bist du krank oder gehörst du zu einer komischen Religion oder lügst du?


Anmelden zum Antworten