Wie ermittle ich den Klassentyp eine Memberfunktionspointers?
-
Dravere schrieb:
Naja, man könnte ein wenig bescheissen, dann geht das auch:
template<typename FuncT, typename ClassT> void bind(ClassT& object); // Verwendung: bind<&A::Foo>(a);&A::Foo ist kein Typ.
-
genau wie audacia.
Hier der code:
template <typename Retval = void> class Delegate { template <typename Class, Retval (Class::*Method) (void)> static Retval methodPointerInvoker (void* data) { return (static_cast <Class*> (data)->*Method) (); } Retval (*invoker) (void*); void* data; public: template <typename Class, Retval (Class::*Method) (void)> void bind (Class* obj) { data = obj; invoker = methodPointerInvoker <Class, Method>; } template<typename Func, typename Class> void bind(Class* obj){ data = obj; invoker = methodPointerInvoker <Class, Func>; } }; struct A{ void foo(){} }; int main(int argc, char** argv){ A a; Delegate<void> dg, dg1; dg.bind<A, &A::foo>(&a); dg1.bind<&A::foo>(&a); return 0; }das erste bind funktioniert und bei zweiten weiss der compiler nicht, was er machen soll
Fehlermeldung des compilers
Delegate.cc::33: error: no matching function for call to ‘Delegate<void>::bind(A*)’über weitere Vorschläge würde ich mich freuen.
Gruß
-
Ehm, natürlich, audacia, hast recht. Hmmm, ich glaube ich sollte besser ins Nest gehen. Bin heute schon viel zu lange auf den Beinen ...
Ich werde mir das morgen/heute nochmals genauer anschauen. Vielleicht hat in der Zwischenzeit jemand eine Idee...Grüssli
-
Gibe es einen Grund nicht boost::function<> zu verwenden?
boost::function<> ist für "bloss ein gebundener mem-fn-pointer" Fälle optimiert, d.h. es findet beim "binden" keine dynamische Speicherallokation statt.Weiss nicht wozu man sich dann was eigenes stricken sollte.
-
mysterio schrieb:
Genau, so in der Art sieht mein Delegate aus und FastDelegates kenne ich auch. Habe auch schon drüber nachgedacht diese zu nutzen, aber brauchen halt auf dem AVR 33% mehr RAM. Statt 4Byte eben 6Byte. Klingt zwar erstmal nicht wirklich viel, aber wenn man mehrere hat und man bedenkt, dass manche AVR nicht mal 1kB RAM besitzen, muss man schon mal aufpassen.
-
Upps.
Jo hätte ich mal genauer lesen sollen
-
Ich wusste doch, dass es möglich ist. Naja, zumindest habe ich eine Lösung gefunden. Wie gut die ist, darüber lässt sich natürlich streiten. Die Lösung ist ein Proxy, welcher entsprechende Typinformationen mitträgt. Fehlerbehandlungen habe ich noch nicht eingebaut, das überlasse ich gerne dem Anwender, es soll ja nur eine Idee präsentieren:
#include <iostream> template<typename RetT = void> class Delegate { // Static functions // private: template<typename ClassT, RetT (ClassT::*Method)()> static RetT methodPointerInvoker(void* data) { return (static_cast<ClassT*>(data)->*Method)(); } // Structs // private: template<typename ClassT> class Proxy { private: ClassT* m_object; Delegate* m_delegate; public: Proxy(ClassT* object, Delegate* dg) : m_object(object) , m_delegate(dg) { } public: template<RetT (ClassT::*FUNC)()> void set() const { m_delegate->m_invoker = &methodPointerInvoker<ClassT, FUNC>; } }; // Attributes // private: RetT (*m_invoker)(void*); void* m_data; // Operators // public: RetT operator ()() { return (*m_invoker)(m_data); } // Methods // public: template<typename ClassT> Proxy<ClassT> const bind(ClassT* obj) { m_data = obj; return Proxy<ClassT>(obj, this); } }; struct A { void foo() { std::cout << "foo" << std::endl; } }; int main() { A a; Delegate<void> dg; dg.bind(&a).set<&A::foo>(); dg(); return 0; }Grüssli
-
Kleiner Zusatz für Schreibfaule, oder wenn du einfach eine angenehm lesbare Funktion haben willst:
#define BIND_TO_DELEGATE(dg, obj, func) \ dg.bind(obj).set<func>() int main() { A a; Delegate<void> dg; BIND_TO_DELEGATE(dg, &a, &A::foo); dg(); return 0; }Grüssli
-
Ja, diese Version funktioniert soweit gut. Ob sie bzgl. Ressourcen ebenso effizent ist, wie die erste Version weiss ich noch nicht, da ich noch keine genauen Tests gemacht habe. Ich werde es aber mal untersuchen und dann hier schreiben.
Wenn ich es aber richtig ueberblicke, wird sich moeglicherweise nicht viel aendern, da ja nur ein temporaeres Proxy-Objekt angelegt wird und dies kann der Compiler bestimmt wegoptimieren.
Die urspruengliche Frage ist ja auch beantwortet, dass es mit dem aktuellen Standard halt nicht geht, aber im C++0X ein neues Sprachkonstrukt genau dies ermoeglicht.
Auf jeden Fall danke und ich habe mal wieder viel gelernt.
-
Also ich habe mal Groessenmessungen gemacht. Auf dem PC sind mit der Proxyvariante bei -Os Optimierung 16 Byte Text mehr und RAM ist bei beiden gleich, beim RAM sollte es ja auch so sein ... Text ist aber eh nicht ganz so kritisch auch selbst beim AVR nicht.
Dann habe ich auch noch Messungen mit einem avr-g++ gemacht und dort oh Ueberraschung -- beide Varianten liefern hier die gleichen Ergebnisse.
Nun weiss ich nicht ganz, ob es an der Version des Compilers liegt, da ich auf dem PC g++ in Version 4.3.2 und fuer den AVR in Version 4.2.1 benutze.
Bin sonst aber ganz zufrieden. Nochmals Danke.