Hypercell ein ] Hypercell aus ] Zeige Navigation ] Verstecke Navigation ]
c++.net  
   

Die mobilen Seiten von c++.net:
https://m.c-plusplus.net

  
C++ Forum :: VCL (C++ Builder) ::  C++03 konforme Alternative zu __closure?     Zeige alle Beiträge auf einer Seite Auf Beitrag antworten
Autor Nachricht
DocShoe
Mitglied

Benutzerprofil
Anmeldungsdatum: 02.04.2008
Beiträge: 2668
Beitrag DocShoe Mitglied 17:00:18 10.02.2017   Titel:   C++03 konforme Alternative zu __closure?            Zitieren

Hallo,

gibt es eine C++03 konforme Alternative zu dem __closure Konstrukt? Ich brauche eine universelles Publisher/Subscriber Framework, das ohne borland-spezifische Spracherweiterungen auskommt. Pointer-to-member Funktionen ließen sich bisher einfach mit der__closure Erweiterung erschlagen, aber jetzt brauchen wir eine standardkonforme C++ Lösung.

1) boost::signals2
Wird vom Compiler nicht unterstützt. RAD Studio 10.1 liefert zwar die boost Bibliotheken 1.39 mit, allerdings fehlt dort signals2.

2) boost::signal
Ist in den boost Bibliothken 1.39 dabei, wird vom Compiler auch übersetzt, löst aber bei Benutzung eine Access Violation aus.

3) Eigenbau mit boost::bind/boost::function
Totale Katastrophe. Im besten Fall bekomme ich einen internen Compiler Fehler, im schlimmsten Fall hängt der Compiler oder die IDE beendet sich.

Im Grunde brauche ich sowas:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <vector>
 
struct S1
{
   void f( int x )
   {
   }
};
 
struct S2
{
   void f( int x )
   {
   }
};
 
int main()
{
   S1 s1;
   S2 s2;
 
   vector v<MAGIC_HERE> v;
   v.push_back( MAGIC_HERE( &s1, &S1::f ) );
   v.push_back( MAGIC_HERE( &s2, &S2::f ) );
 
   for( vector v<MAGIC_HERE>::const_iterator i = v.begin(); i != v.end(); ++v )
   {
      (*i)( 123 ); // ruft s1.f( 123 ) und s2.f( 123 ) auf
   }
}


Weiß jemand Rat?

_________________
Die fünf häufigsten Anzeichen für Faulheit:
1.


Zuletzt bearbeitet von DocShoe am 17:00:43 10.02.2017, insgesamt 1-mal bearbeitet
Burkhi
Mitglied

Benutzerprofil
Anmeldungsdatum: 12.11.2003
Beiträge: 703
Beitrag Burkhi Mitglied 22:27:43 10.02.2017   Titel:              Zitieren

Ob das comfortabel ist, sei mal dahingestellt, aber ich habe mir vor einiger Zeit mal etwas gebastelt, was solche __closure Konstrukte nachbildet:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#ifndef _CALLBACK_H
#define _CALLBACK_H
/******************************************************************************/
//Makro zur Definition von Callbackklassen
//Name     = Name der CallBackKlasse
//Params   = Auflistung der zu übergebenen Parameter mit Typangabe (Typ Name)
//           Die auflistung ist in Klammern zu setzen, die Parameter sind
//           mit Komma zu trennen
//VarNames = Übergebene Parameter ohne Typangabe, d.h. hier noch einmal alle
//           Parameter aufzählen ohne Typ und Modifizierer.
//
//*******************************************************************************

#define DEFINECALLBACK(Name,Params,VarNames) \

    class Name{\
    public:\
        virtual void operator() Params =0;\
    };\
    \
    template <class TEvClass> class CB_##Name : public Name{\
    public:\
        typedef void (TEvClass::*Event_t) Params;\
    CB_##Name(TEvClass* pEvClass, Event_t pEvMethod): m_pClass(pEvClass),m_pEvent(pEvMethod){}\
    protected:\
        void operator() Params {(m_pClass->*m_pEvent) VarNames;}\
    private:\
        TEvClass*  m_pClass;\
        Event_t    m_pEvent;\
    };
/********************************************************************************/
// Makro zur Erzeugung des Callbacks
// Name      = Name der Callbackklasse (von DEFINECALLBACK)
// ClassName = Klassename, zur der die aufzurufende Methode gehört
// Method    = Name der aufzurufenden Methode

#define CREATECALLBACK(Name,ClassName,Method) new CB_##Name<ClassName>(this,&ClassName::Method)

/********************************************************************************/

#endif


Beispiel:
Das Event soll "DataEvent" heissen und hat als Parameter einen Zeiger
auf Daten und einen integer-Wert, der die Anzahl angeben soll:

C++:
DEFINECALLBACK(DataEvent,(void *Data, int count),(Data, count))


Das Objekt, welches das Event aufrufen soll, sei "reader".

Eine Klasse "CSerialData" soll eine Methode "OnData" erhalten, die aufgerufen
werden soll. Diese soll vom Typ "DataEvent" sein, daher sieht sie also so aus:

C++:
void OnData (void *Data, int count)


OnData soll von Objekt reader aufgerufen werden. Dazu muss dieses dann eine
Membervariable definieren, die vom Typ DataEvent ist:

C++:
DataEvent *FOnData;


Dafür am besten eine Set-funktion definieren:

C++:
void SetOnData(DataEvent *Value)
{
 delete FOnData; //muss im Konstruktor mit 0 initialisiert werden!!!
         //sorgt dafür, das bei Neuzuweisung das alte Event
             //gelöscht wird.
  FOnData = Value;
}


Die Zuweisung wird nun von der Klasse ausgeführt, die die Methode "OnData" enthält,
im Beispiel also innerhalb der Klasse CSerialData:

C++:
reader.SetOnData(CREATECALLBACK(DataEvent,CSerialData,OnData));


Hier einmal als kompletter Code:



C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
 DEFINECALLBACK(DataEvent,(void *Data, int count),(Data, count));
 
 class CReader
 {
 public:
     CReader() : FOnData(0) {}
     ~CReader() { SetOnData(0);};
 
     void SetOnData(DataEvent *Value)
     {
         delete FOnData;
         FOnData = Value;
     }   
 
   void Datenempfangen()
     {
         //.....
         if (FOnData)
         {
           (*FOnData)(Data,Len);
         }
     }
 
 private:
   DataEvent *FOnData;  
 };
 
 class CSerialData
 {
 public:
   CSerialData()
     {
         reader.SetOnData(CREATECALLBACK(DataEvent,CSerialData,OnData));
     }
 private:
     CReader reader;
 
     void OnData(void *Data, int count)
     {
         //.....
     }
 };


Ev. ist das ja was für dich.

_________________
Objekt- Orientierte Automatisierungs- Software- Entwicklung
Rad Studio: 10.2 Tokyo, 10.1 Berlin, 10 Seattle, XE8, XE7, XE6, XE5, XE2, XE, 2010, 2009
C++ Builder: XE4, XE3, 2006, 5 Prof
audacia
Mitglied

Benutzerprofil
Anmeldungsdatum: 05.02.2005
Beiträge: 4712
Beitrag audacia Mitglied 15:06:39 11.02.2017   Titel:   Re: C++03 konforme Alternative zu __closure?            Zitieren

DocShoe schrieb:
3) Eigenbau mit boost::bind/boost::function
Totale Katastrophe. Im besten Fall bekomme ich einen internen Compiler Fehler, im schlimmsten Fall hängt der Compiler oder die IDE beendet sich.
Auch mit std::function<>? Oder ist das immer noch dieselbe Implementierung wie boost::function<>?

Ich erinnere mich, daß ich früher (RAD Studio XE) boost::function<> und std::bind() ohne Probleme benutzen konnte. Wenn das in neueren Versionen nicht mehr geht, hat wohl jemand das QA-Department wegrationalisiert.


Wie dem auch sei: den Klassiker zum Thema kennst du vermutlich?
https://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible
Und dieses Follow-up?
https://www.codeproject.com/Articles/11015/The-Impossibly-Fast-C-Delegates
Vielleicht ist das ja eine stabilere Grundlage für dich.

_________________
"Hey, it compiles! Ship it!"
C++Builder Pages · Typsichere Format-Strings
DocShoe
Mitglied

Benutzerprofil
Anmeldungsdatum: 02.04.2008
Beiträge: 2668
Beitrag DocShoe Mitglied 16:05:47 13.02.2017   Titel:              Zitieren

Danke für die Hinweise,

im Moment fehlt mir leider die Zeit, mir das im Detail anzugucken.

@Burkhi:
Was mir an deiner Lösung nicht so gefällt ist das Hantieren mit besitzenden Zeigern und die damit notwendige Speicherverwaltung. Evtl. kann man das in einen shared_ptr verpacken.

@Audacia:
Ja, kenne ich, hab mir da auch ein paar Sachen abgeguckt. Was mir an den impossibly fast C++ delegates nicht gefällt ist, dass der Typ der Memberfunktion als Template Parameter übergeben wird und die Konstruktiond dadurch etwas umständlich wird. Aber das kriegt man sicher durch nen Wrapper hin. Muss mir das aber noch mal genauer angucken.

Und was das RAD Studio angeht:
Es hatte wohl einen schlechten Tag. Heute war´s besser drauf und ist zumindest nicht abgestürzt, als ich boost::bind/function benutzt habe. Übersetzen tut´s trotzdem nicht :/

_________________
Die fünf häufigsten Anzeichen für Faulheit:
1.


Zuletzt bearbeitet von DocShoe am 16:07:14 13.02.2017, insgesamt 3-mal bearbeitet
audacia|off
Unregistrierter




Beitrag audacia|off Unregistrierter 18:23:53 13.02.2017   Titel:              Zitieren

[quote = "DocShoe"]Was mir an den impossibly fast C++ delegates nicht gefällt ist, dass der Typ der Memberfunktion als Template Parameter übergeben wird und die Konstruktiond dadurch etwas umständlich wird.Aber das kriegt man sicher durch nen Wrapper hin.[/quote]Leider nur mit Makro und decltype().


Hier mal ein auf den "impossibly fast delegates" aufbauender Versuch, der mit VC++ und g++ kompiliert:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include <type_traits>
#include <cstdio>
 
 
template <typename FuncT>
    class Delegate;
template <typename R, typename... Args>
    class Delegate<R(Args...)>
{
private:
    typedef R (*Stub_)(void*, Args...);
 
    void* data;
    Stub_ code;
 
    Delegate(void* _data, Stub_ _code)
        : data(_data), code(_code)
    {
    }
    template <typename C, R (C::*Func)(Args...)>
        static R methodStub(void* obj, Args... args)
    {
        return (static_cast<C*>(obj)->*Func)(args...);
    }
    template <typename C, R (C::*Func)(Args...) const>
        static R constMethodStub(void* obj, Args... args)
    {
        return (static_cast<const C*>(obj)->*Func)(args...);
    }
    template <typename C, R (*Func)(C*, Args...)>
        static R functionStub(void* obj, Args... args)
    {
        return Func(static_cast<C*>(obj), args...);
    }
 
public:
    Delegate(void)
        : data(nullptr), code(nullptr)
    {
    }
    Delegate(const Delegate& rhs) = default;
    Delegate(Delegate&& rhs)
        : data(rhs.data), code(rhs.code)
    {
        rhs.data = nullptr;
        rhs.code = nullptr;
    }
    Delegate& operator =(const Delegate& rhs) = default;
    Delegate& operator =(Delegate&& rhs)
    {
        data = rhs.data;
        code = rhs.code;
        rhs.data = nullptr;
        rhs.code = nullptr;
        return *this;
    }
 
    template <typename C, R (C::*Func)(Args...)>
        static Delegate<R(Args...)> fromMethod(C* obj)
    {
        return Delegate<R(Args...)>(static_cast<void*>(const_cast<typename std::remove_const<C>::type*>(obj)), methodStub<C, Func>);
    }
    template <typename C, R (C::*Func)(Args...) const>
        static Delegate<R(Args...)> fromConstMethod(const C* obj)
    {
        return Delegate<R(Args...)>(static_cast<void*>(const_cast<C*>(obj)), constMethodStub<C, Func>);
    }
    template <typename C, R (*Func)(C*, Args...)>
        static Delegate<R(Args...)> fromFunction(C* obj)
    {
        return Delegate<R(Args...)>(static_cast<void*>(const_cast<typename std::remove_const<C>::type*>(obj)), functionStub<C, Func>);
    }
 
    R operator ()(Args... args) const
    {
        return code(data, args...);
    }
};
 
template <typename FuncT>
    struct DelegateHelper_;
template <typename C, typename R, typename... Args>
    struct DelegateHelper_<R (C::*)(Args...)>
{
    template <R (C::*Func)(Args...)>
        static Delegate<R(Args...)> makeDelegate(C* obj)
    {
        return Delegate<R(Args...)>::template fromMethod<C, Func>(obj);
    }
};
template <typename C, typename R, typename... Args>
    struct DelegateHelper_<R (C::*)(Args...) const>
{
    template <R (C::*Func)(Args...) const>
        static Delegate<R(Args...)> makeDelegate(const C* obj)
    {
        return Delegate<R(Args...)>::template fromConstMethod<C, Func>(obj);
    }
};
template <typename C, typename R, typename... Args>
    struct DelegateHelper_<R (*)(C*, Args...)>
{
    template <R (*Func)(C*, Args...)>
        static Delegate<R(Args...)> makeDelegate(C* obj)
    {
        return Delegate<R(Args...)>::template fromFunction<C, Func>(obj);
    }
};

#define DELEGATE_METHOD(obj,memfun) (DelegateHelper_<decltype(memfun)>::template makeDelegate<memfun>(obj))

#define DELEGATE_FUNCTION(obj,fun) (DelegateHelper_<decltype(fun)*>::template makeDelegate<fun>(obj))



Test:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Test
{
private:
    float f;
 
public:
    Test(float _f) : f(_f) { }
    float foo(double d) { f += float(d); return f; }
    float bar(double d) const { return f + float(d); }
};
 
float freeFoo(Test* self, double d) { return self->foo(d); }
float freeBar(const Test* self, double d) { return self->bar(d); }
 
int main(void)
{
    Test t(42.f);
   
    Delegate<float(double)> d1, d2, d3, d4;
 
    d1 = DELEGATE_METHOD(&t, &Test::foo);
    d2 = DELEGATE_METHOD(&t, &Test::bar);
    d3 = DELEGATE_FUNCTION(&t, freeFoo);
    d4 = DELEGATE_FUNCTION(&t, freeBar);
 
    std::printf("d1(%g) = %g\n", 1.f, d1(1.f));
    std::printf("d2(%g) = %g\n", 1.f, d2(1.f));
    std::printf("d3(%g) = %g\n", 1.f, d3(1.f));
    std::printf("d4(%g) = %g\n", 1.f, d4(1.f));
}


Mit decltype sollte der BCC eigentlich klarkommen. Ich überlasse dir die Fleißarbeit, die variadic templates und Default-Kopierkonstruktor und -Zuweisungsoperator nach C++03 zu portieren :)
Burkhi
Mitglied

Benutzerprofil
Anmeldungsdatum: 12.11.2003
Beiträge: 703
Beitrag Burkhi Mitglied 00:43:19 15.02.2017   Titel:              Zitieren

DocShoe schrieb:
...

@Burkhi:
Was mir an deiner Lösung nicht so gefällt ist das Hantieren mit besitzenden Zeigern und die damit notwendige Speicherverwaltung. Evtl. kann man das in einen shared_ptr verpacken.

...


Ich hatte das in der Zwischenzeit auch schon etwas verbessert. ;)

_________________
Objekt- Orientierte Automatisierungs- Software- Entwicklung
Rad Studio: 10.2 Tokyo, 10.1 Berlin, 10 Seattle, XE8, XE7, XE6, XE5, XE2, XE, 2010, 2009
C++ Builder: XE4, XE3, 2006, 5 Prof
asc
Mitglied

Benutzerprofil
Anmeldungsdatum: 13.01.2007
Beiträge: 6641
Beitrag asc Mitglied 13:19:22 15.02.2017   Titel:              Zitieren

DocShoe schrieb:

Und was das RAD Studio angeht:
Es hatte wohl einen schlechten Tag. Heute war´s besser drauf und ist zumindest nicht abgestürzt, als ich boost::bind/function benutzt habe. Übersetzen tut´s trotzdem nicht :/


Ich wüsste zwar nicht wann das RAD Studio überhaupt einmal einen guten Tag hätte, aber in unseren Projekt nutzten wir bind/function (glaube seit dem XE4), wobei die Schreibweise [z.B. ] in Einzelfall nicht dem Standard entspricht.

So nutzen wir z.B. boost::function1(X, Y) statt std::function(X (Y)) [X und Y durch den entsprechenden Rückgabetyp und Parametertyp ersetzen].

_________________
in theory there's no difference between theory and practice. in practice there is. (yogi berra)

In der Theorie gibt es kein Unterschied zwischen Theorie und Praxis. In der Praxis sehr wohl.
DocShoe
Mitglied

Benutzerprofil
Anmeldungsdatum: 02.04.2008
Beiträge: 2668
Beitrag DocShoe Mitglied 14:44:37 16.02.2017   Titel:              Zitieren

Ich habe mich jetzt noch mal mit boost::function beschäftigt, der Fehler lag bei mir. Wenn man sie richtig benutzt funktionieren sie auch ;)

_________________
Die fünf häufigsten Anzeichen für Faulheit:
1.
C++ Forum :: VCL (C++ Builder) ::  C++03 konforme Alternative zu __closure?   Auf Beitrag antworten

Zeige alle Beiträge auf einer Seite




Nächstes Thema anzeigen
Vorheriges Thema anzeigen
Sie können Beiträge in dieses Forum schreiben.
Sie können auf Beiträge in diesem Forum antworten.
Sie können Ihre Beiträge in diesem Forum nicht bearbeiten.
Sie können Ihre Beiträge in diesem Forum nicht löschen.
Sie können an Umfragen in diesem Forum nicht mitmachen.

Powered by phpBB © 2001, 2002 phpBB Group :: FI Theme

c++.net ist Teilnehmer des Partnerprogramms von Amazon Europe S.à.r.l. und Partner des Werbeprogramms, das zur Bereitstellung eines Mediums für Websites konzipiert wurde, mittels dessen durch die Platzierung von Werbeanzeigen und Links zu amazon.de Werbekostenerstattung verdient werden kann.

Die Vervielfältigung der auf den Seiten www.c-plusplus.de, www.c-plusplus.info und www.c-plusplus.net enthaltenen Informationen ohne eine schriftliche Genehmigung des Seitenbetreibers ist untersagt (vgl. §4 Urheberrechtsgesetz). Die Nutzung und Änderung der vorgestellten Strukturen und Verfahren in privaten und kommerziellen Softwareanwendungen ist ausdrücklich erlaubt, soweit keine Rechte Dritter verletzt werden. Der Seitenbetreiber übernimmt keine Gewähr für die Funktion einzelner Beiträge oder Programmfragmente, insbesondere übernimmt er keine Haftung für eventuelle aus dem Gebrauch entstehenden Folgeschäden.