Wie ermittle ich den Klassentyp eine Memberfunktionspointers?
-
Stimmt schon, dass man boost verwenden könnte, aber ich programmiere für eine Plattform (AVR) die nicht so richtig
von boost unterstützt wird. Und außerdem ist meine Delegatevariante ressourcenschonender. Ich brauche weniger RAM als die boost delegates über boost::function und auf einem microcontroller ist dies halt von Bedeutung. Aber sei es drum, ansonsten hast Du recht und ich würde sonst immer zu boost greifen, .....Nun aus oben genannten Gründen und natürlich auch aus Interesse versuche ich halt einen anderen möglichen Weg. Ich kann auch mit meiner ursprünglichen Form
db.bind<A, &A::foo>(&a);leben, aber schöner wäre die direkte Bestimmung der Klasse aus dem Templateparameter. Wäre halt übersichtlicher meines erachtens.
@audacia
das mit dem C++0x geht. Die Frage ist, ob es auch mit den bisherigen Bortmitteln des aktuellen Standards geht.Grüße
-
Dravere schrieb:
Seltsames bind ... Schreib das Ding doch um: [...]
Das schränkt die Möglichkeiten deutlich ein. Mit seiner bind()-Methode kann er so etwas machen:
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>; } };Sicher, auch das hat Nachteile, aber es macht Delegates ein gutes Stück effizienter.
Allerdings würde ich als Workaround für dieses fundamentale Sprachdefizit von C++ Fast Delegates empfehlen. boost::function ist ganz nett, aber wundervoll ineffizient.
mysterio schrieb:
das mit dem C++0x geht. Die Frage ist, ob es auch mit den bisherigen Bortmitteln des aktuellen Standards geht.
Leider nicht.
-
@mysterio,
Aber nicht Atmel AVR?
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);Grüssli
-
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.
@Dravere
Doch Atmel AVR und ich werde deinen Vorschlag mal testen.Danke nochmals für eure Hilfe
-
@Dravere
leider funktioniert es nicht mit dem von Dir vorgeschlagenen bind zumindest nicht bei mir. Vielleicht habe ich auch was falsch gemacht, aber ich habe es einfach mal im code von audacia getestet und es führte leider nicht zum Erfolg.Gruß
-
@mysterio,
1. Geht nicht, ist keine Fehlerbeschreibung.
2. Was genau hast du gemacht?
Und zu Atmel AVR ... WAAAAAARRRRGGGHHHH
Da habe ich letztes Jahr grauenhafte Assemblererfahrungen damit gemacht
Grüssli
-
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.