Pointer innerhalb Klasse auf Memberfunktion



  • Ich werde es mir anschauen. Ich habe es auf die schnelle erst ein mal so gelöst:

    template< typename THREAD_ROUTINE >
    struct ThreadProxyData
    {
    	THREAD_ROUTINE	 lpFunction;
    	THREAD_DATA		 lpParams;
        ThreadProxyData( THREAD_ROUTINE start_address, THREAD_DATA arglist) : 
    					 lpFunction(start_address), lpParams(arglist) {}
    };
    

    Diese struct wird jetzt dem Konstruktor übergeben. Insofern ist dort bereits festgelegt, wie die Funktion aussieht. Intern rufe ich dann eine andere Funktion des Typs unsigend (__stdcall *Func)(void*) auf, welche wiederum dann diese Funktion aufruft.

    Ist eine - denke ich - ganz gute Lösung.



  • Wie ich nun einen Zeiger auf eine Klassenmethode bekomme hat sich dadurch natürlich immer noch nicht geklärt. Ich löse das jetzt wie folgt:

    // Funktion außerhalb Klasse
    unsigned int __stdcall __callAccept(void* _instance)
    {
    	while( TRUE ) {
    		static_cast<HClasses::ServerSocket*>(_instance)->_accept( NULL );
    	}
    	return 0;
    }
    
    // innerhalb Klasse
    	this->_acceptThread = new Threading::HThread( __callAccept,
    		                                          this,
    												  HClasses::Threading::PREPARED,
    												  false                           );
    

    Naja, eine wenig schöne Lösung. Fällt jemandem eine elegantere Art ein?



  • Ein Zeiger auf eine nicht-statische Elementfunktion ist nicht kompatibel zu einem Zeiger auf eine freie Funktion. Es gibt auch keine Zeiger auf "gebundene" Elementfunktionen.

    Das, was Du jetzt geschrieben hast, ist in etwa das gleiche, was ich als erste Antwort in diesem Thread geschrieben habe. Es ist erstaunlich, wie lange es gedauert hat...

    Fällt mir etwas eleganteres ein? Naja, im Prinzip kommst Du um so etwas nicht herum. Man kann aber diesen Proxy-Schnickschnack hinter der Threading-Bibliothek verstecken. Das wär dann nach meinem Empfinden elegant. Das sage ich allerdings auch nicht zum ersten Mal. Und bevor ich mich weiter wiederhole, werde ich jetzt mal ganz direkt: Du demonstrierst Inkompetenz. Das allein ist keine Schande. Es ist noch kein Meister vom Himmel gefallen. Du bist aber nicht in der Lage gewesen, anhand der Hinweise und Tipps, die man Dir gab, Dir selbst zu helfen. Das ist eine sehr schlechte Voraussetzung zum Schreiben einer eigenen Threading-Bibliothek. Was erwartest Du? Dass man Dir hier eine Komplettlösung anbietet? Das kannst Du haben: Nimm boost::thread. Wenn Du etwas ähnliches selbst bauen willst, bitte. Du kannst dann eine Suchmaschine zu den Stichwörtern befragen, die hier gefallen sind und selbst eine Lösung erarbeiten.

    Gruß,
    SP



  • Ich bleibe mal ruhig und behaupte wir reden einfach ständig aneinander vorbei.

    Ich bin mir darüber im klaren, dass die jetzige Lösung genau das ist, was du am Anfang vorgeschlagen hast. Ich habe "damals" gesagt, dass ich die Lösung nicht schön finde und sage jetzt, dass ich "meine" Lösung nicht schön finde.
    Alles sehr logisch, würde ich sagen.

    Meine Frage war doch einfach nur, ob es INNERHALB der Klasse möglich ist (ohne von außen zu kommen) einen Zeiger auf eine Memberfunktion zu bekommen.
    Der Grund, warum es so lange gedauert hat, war eher der, dass ich keine "eindeutige" Verneinung bekommen habe.

    Die Lösung die wir jetzt haben war mir schon eingefallen, bevor ich diesen Thread geschrieben habe, daher war ich auch überhaupt nicht darauf eingegangen (worüber du dich dann später aufgeregt hast), weil es unsauber ist.

    Ich habe mich derweil auch mal ein bisschen mit boost::function auseinander gesetzt. Es dient zwar überhaupt nicht mehr meiner Problemlösung, aber schien mir doch recht interessant zu sein.

    Anhand von "function.hpp" entnehme ich, dass es sich dabei im Prinzip um eine Verschachtelung von templates handelt. Man übergibt typename Signature, was intern dann aufgesplittet wird (siehe function0 .. function10).

    Was mich jetzt interessieren würde, ist, wie man denn den übergebenen Funktionstyp "auswertet" (falsches Wort, schon klar 😉

    angenommen es wird folgendes übergeben:

    boost::function<typename Signature>
    boost::function<int(int,int,int)> f = foo;
    

    innerhalb der Klasse haben wir dann:

    boost::function3<typename R, typename T1, typename T2, typename T3>
    boost::function3<int,int,int,int>
    

    Mich würde interessieren, wie man den ursprünglich übergebenen Typ auswerten kann.

    char* _type = typeid(f).name();
    

    hilft einem nicht viel weiter.

    Ich würde mich freuen, wenn wir das so schön klären könnten, wie das vorherige Thema.


  • Administrator

    FrEEzE2046 schrieb:

    Ich bleibe mal ruhig und behaupte wir reden einfach ständig aneinander vorbei.

    Da habe ich so meine Zweifel, ich könnte mir eher vorstellen, dass du Sebastian Pizer nicht verstanden hast und das aus einem simplen Grund, weshalb ich dir nun eine Frage stelle:
    Wo stehst du in Sachen C++ lernen? Ich persönlich habe das Gefühl, dass du hier ein für dein Wissen viel zu fortgeschrittenes Thema angehen möchtest. Dir fehlen also meiner Meinung nach Grundlagen. Und ohne diese Grundlagen, ist es natürlich eher schwer, dir in dem Bereich zu helfen.

    Was hast du bereits über C++ gelesen, wenn ich mir die Frage erlauben darf? Vielleicht können wir dir entsprechende Literatur vermitteln, welche du zuerst lesen könntest.

    Grüssli



  • Offensichtlich habe ich Probleme mich richtig auszudrücken. Ich denke nicht, dass ich hier etwas versuche, was ich nicht richtig begreife.

    Zugegeben: Mit Templates arbeite ich gewöhnlich nicht, daher auch die letzte Frage. Aber Threads oder Sockets habe ich schon oft erstellt, nur eben nie für eine Methode innerhalb einer Klasse.

    Das ich die Möglichkeit der statischen Deklaration oder des externen Aufrufs habe, wusste ich bereits vorher. Ich dachte nur, dass mir jemand noch eine geschicktere Variante verraten kann.
    Man darf da nicht so kurzsichtig sein. Die Frage sollte irgendwo auch darauf abzielen, dass jemandem vielleicht ein generell anderer Lösungsweg einfällt; das war nicht unbedingt beschränkt auf den Methoden-Pointer.



  • FrEEzE2046 schrieb:

    Ich habe mich derweil auch mal ein bisschen mit boost::function auseinander gesetzt. Es dient zwar überhaupt nicht mehr meiner Problemlösung, aber schien mir doch recht interessant zu sein.

    ...

    Was mich jetzt interessieren würde, ist, wie man denn den übergebenen Funktionstyp "auswertet" (falsches Wort, schon klar 😉

    Hier ist eine halbwegs überschaubare Implementierung auf Basis von C++0x: click. Sie ist nicht perfekt und vielleicht auch nicht besonders leserlich aber das Prinzip sollte klar werden.


  • Administrator

    FrEEzE2046 schrieb:

    Offensichtlich habe ich Probleme mich richtig auszudrücken.

    Kann sein, zum Teil empfand ich es als sehr verwirrend, wie du geantwortet hast. Ich bin mir das oft gewohnt davon, wenn der andere sich nicht so gut im Thema auskennt.

    FrEEzE2046 schrieb:

    Ich denke nicht, dass ich hier etwas versuche, was ich nicht richtig begreife.

    Ich kann es nicht genau beurteilen, solange ich nicht deinen genauen Wissensstand kenne, was man eben mit der Literatur zumindest teilweise hätte feststellen können 😉

    FrEEzE2046 schrieb:

    Man darf da nicht so kurzsichtig sein. Die Frage sollte irgendwo auch darauf abzielen, dass jemandem vielleicht ein generell anderer Lösungsweg einfällt; das war nicht unbedingt beschränkt auf den Methoden-Pointer.

    Im allgemeinen geht man über eine statisch oder globale Funktion und übergibt einen Zeiger auf eine Struktur. Das geht auch gar nicht gross anders, weil es so von den Betriebsystemen vorgeschrieben ist.
    Die Threading Bibliothek kapselt dieses nicht so schöne Aussehen und gibt einem ein allgemeingültiges Interface. Was zum Beispiel eben auch boost::thread macht.

    Nun ist halt die Frage, was willst du genau? Steigst du auf boost::thread um oder kapselst du lieber deine Threading Bibliothek und erstellst dir eine eigene, was aber mit ziemlich viel Arbeit verbunden ist. Sowas zu erstellen ist nicht gerade von heute auf morgen fertig und man sollte dabei schon auch in Templates gefestigt sein.

    Was genau möchtest du also nun von uns hören? Wenn du mehr über Templatemetaprogrammierung wissen willst, dann kann ich dir auch ein oder zwei Bücher empfehlen.

    Grüssli



  • Sebastian Pizer schrieb:

    Hier ist eine halbwegs überschaubare Implementierung auf Basis von C++0x: click. Sie ist nicht perfekt und vielleicht auch nicht besonders leserlich aber das Prinzip sollte klar werden.

    Was ich nicht verstehe ist diese Zeile:

    template<typename R, typename ... P>
    

    Ich bekomme da logischerweiße einen Compilerfehler

    missing ',' before '...'
    

    Was genau soll obige Deklaration bedeuten? Eine nichtdefinierte Parameterliste? Wenn ja, wie spreche ich die übergebenen Werte an?





  • Ich benutze das Visual Studio 2008 Team System. Gibt es eine Möglichkeit C++ 0x Code dort zu kompilieren?

    Laut MSDN Blog sollen Variadic Templates ja nicht mal in VS 10 möglich sein. Welcher Compiler kann das schon jetzt?





  • Ja, dass habe ich mittlerweile schon gesehen. Boost::Function benutzt aber keine variable Parameterliste für seine templates.

    Ich muss allerdings zugeben, dass ich die Vorgehensweiße dort nicht ganz verstehe. Mich interessiert die herangehensweiße schon sehr muss ich sagen. Allerdings möchte ich ungern a) einen anderen Compiler konfigurieren, zu mal ich Windows-User bin und b) einen "Standard" nutzen, der (noch) keiner ist.

    Zudem geht auch boost anders an die Thematik heran. Fragt sich nur wie ...



  • .........

    class keksdose
    {
    public:
      void startthread(void *arg)
      {
        threaddata t;
        t.this_pointer = this;
        t.arg = arg;
        t.function = &keksdose::myfunction;
        CreateThread(0, 0, proxy, this, 0, 0);
      }
    private:
      struct threaddata
      {
        void (keksdose::*function)(void *);
        void *arg;
        keksdose *this_pointer;
      };
      DWORD STDCALL proxy(void *vptr)
      {
        threaddata *t = static_cast<threaddata *>(vptr);
        t->this_pointer->*(t->function)(t->arg);
        return 0;
      }
      void myfunction(void *arg)
      {
         for (;;)
           Sleep(1000);
      }
    };
    

    ka ob das läuft



  • Sebastian Pizer schrieb:

    Vom GCC unterstützte C++0x Sprachfeatures.
    Status der C++0x-Std-Library Implementierung (libstdc++).

    Laut MSDN unterstützt das Visual Studio 2008 nach Installation des Visual C++ Feature Packs auch Variadic Templates( siehe: tuple Class ).

    Bei mir will die Syntax aber so noch nicht funktionieren. Kann da jemand was zu sagen?



  • FrEEzE2046 schrieb:

    Bei mir will die Syntax aber so noch nicht funktionieren. Kann da jemand was zu sagen?

    Nein. Man könnte bestenfalls raten was da "so noch nicht funktioniert". Wenn du den Code postest, der nicht funktioniert (am besten mit der Fehlereldung zusammen), dann sind die Chancen gleich viel besser dass dir jeman helfen kann.

    Siehe auch hier.



  • FrEEzE2046 schrieb:

    Laut MSDN unterstützt das Visual Studio 2008 nach Installation des Visual C++ Feature Packs auch Variadic Templates

    Da irrst Du Dich. Das was auf deren Webseite steht ist "nur" Dokumentation und kein kompilierbarer Code. Die haben dort "..." stehen, um zu zeigen, dass man tuple<> so benutzen kann, als wäre es ein variadisches Template. Es ist aber keins, weil sie die noch nicht unterstützen -- auch noch nicht in der aktuellsten Beta-Version.

    Ich habe schon ein PDF von hier verlinkt, was genau beschreibt, wie versch. Dinge (function, tuple, ...) zur Zeit ohne variadische Templates implementiert werden und wie sich die Implementierung mit variadischen Templates stark vereinfachen lässt. Du hast es anscheinend nicht sorgfältig genug gelesen.

    Nebenbei: Hier gibt's ein paar nette Artikel zur Benutzung von Threads unter C++0x.



  • Sebastian Pizer schrieb:

    Ich habe schon ein PDF von hier verlinkt, was genau beschreibt, wie versch. Dinge (function, tuple, ...) zur Zeit ohne variadische Templates implementiert werden

    Wenn du das hier meinst:

    Doch das habe ich mir sorgfältig angeschaut, aber auch dort benutzen sie doch '...'

    siehe:

    template<typename... Args> struct count;
    

    Oder meinstest du ein anderes PDF?


  • Administrator

    @FrEEzE2046,
    Am Anfang des PDFs wird aber erklärt, wie man es bisher in den C++ Bibliotheken gemacht hat. Und genau so macht es auch Boost.Function, Boost.Bind usw.
    Zudem wird auf Boost.Preprocessor verwiesen, was man zur Hilfe heranziehen kann, was bei Boost für das Simulieren von variadic templates auch gemacht wird.

    Grundsätzlich steht alles da am Anfang von Kapitel 2. Es ist sehr kurz gehalten, aber fasst es eigentlich vollständig zusammen.

    Grüssli


  • Administrator

    Sorry für den Doppelpost, aber da schon einige Zeit vergangen ist, wollte ich nicht nur ein Edit machen. Hier noch ein kurzes dahingerotztes Beispiel 🙂

    #include <iostream>
    
    #include <boost/preprocessor.hpp>
    
    #define MY_MACRO_TEMPLATE_TYPES(z, n, data) , typename T##n
    #define MY_MACRO_TEMPLATE_ARGS(z, n, data) , T##n const& arg##n
    #define MY_MACRO_TEMPLATE_OUTPUT(z, n, data) << arg##n
    
    #define MY_MACRO_PRINT_FUNCTION(z, n, data) \
    template<typename T0 BOOST_PP_REPEAT_FROM_TO(1, n, MY_MACRO_TEMPLATE_TYPES, data)>\
    void print(T0 const& arg0 BOOST_PP_REPEAT_FROM_TO(1, n, MY_MACRO_TEMPLATE_ARGS, data)) \
    { \
        std::cout BOOST_PP_REPEAT(n, MY_MACRO_TEMPLATE_OUTPUT, data) ;\
    } \
    
    #define MY_MACRO_CREATE_PRINT_FUNCTIONS(n) \
        BOOST_PP_REPEAT_FROM_TO(1, BOOST_PP_INC(n), MY_MACRO_PRINT_FUNCTION, _)
    
    MY_MACRO_CREATE_PRINT_FUNCTIONS(10)
    
    int main()
    {
        print("Hello", " World", '!', '\n', "Test: ", 443, '\n');
    
        return 0;
    }
    

    Die maximale Anzahl an Parametern ist 10. Also quasi Variadic Templates beschränkt auf 10 Parametern. Das ganze präsentiert an einer print Funktion. Sieht hässlich aus, nicht? 😃
    Variadic Templates aus C++0x werden diese Hässlichkeiten hoffentlich entfernen können 😉

    Grüssli


Anmelden zum Antworten