2016-05-02 9 views
0

Mein C++ ist rostig. Ich möchte, dass MyClass nichts über Foo weiß und einen Rückruf hat, um eine Funktion in foo auszuführen. Ich weiß nicht, wie callback_pair definieren oder wie setCallbackRückruf einer unbekannten Klasse + Funktion

class MyClass{ 
    tuple<cb, ptr> callback_pair 

    int run() { 
     auto that=callback_pair<1>(); 
     auto cb = callback_pair<0>(); 
     int a=1, b=2, c=3; 
     auto result = cb(that, a, b, c); //this calls foo.the_function 
     return result; 
    } 
    void SetCallback(tuple<cb, ptr> cb) { callback_pair=cb;) 
}; 

class Foo { 
    int d; 
    int the_func(int a, b, c) { 
     return a+b+c+d 
    } 
} 
//myclass.SetCallback(what_do_I_write_here) 
+0

Ich habe eine Problemumgehung durch Erstellen einer virtuellen Klasse erstellt. MyClass weiß davon, Foo implementiert es. Aber ich hätte gerne eine Antwort näher zu dem, was ich gefragt habe –

+0

Wir haben jetzt 'std :: function' und' std :: bind'. –

Antwort

1

Nun rufen, MyClass muss wissen etwas über Foo, nämlich die Unterschrift Egal welche Methode Sie planen, als Rückruf zur Verwendung; Wie würde es sonst wissen, was als Parameter übergeben werden soll oder welchen Typ erwartet man als Ausgabe? Wenn der Callback-Signatur bekannt und fixiert ist, zum Beispiel int(int,int,int) wie Sie oben haben, könnten Sie eine Konstruktion wie folgt verwenden:

class MyClass { 
    std::function<int(int,int,int)> callback; 

public: 
    int run() { 
     return callback(1,2,3); // or whatever 
    } 

    template <typename Class> 
    void SetCallback (Class& o, int (Class::*m) (int,int,int)) { 
     callback = [&o,m] (int a, int b, int c) { return (o.*m)(a,b,c); }; 
    } 

    template <typename Class> 
    void SetCallback (Class const& o, int (Class::*m) (int,int,int) const) { 
     callback = [&o,m] (int a, int b, int c) { return (o.*m)(a,b,c); }; 
    } 
}; 

Die obige Umsetzung MyClass funktioniert wie folgt: callback ein Funktionsobjekt ist zunächst nicht definiert, Das dauert drei int s und gibt eine int zurück. SetCallback benötigt zwei Parameter: Ein Objekt o, auf dem der Callback ausgeführt werden soll, und eine Methode m für dieses Objekt, die der Signatur callback entspricht. Es ist egal, was der Typ o ist; Dank Type-Erasure, MyClass muss nie wissen, was es eigentlich anruft.

Beachten Sie die beiden Versionen SetCallback - je eine für const und nicht const Objekte. In Wirklichkeit sollten Sie auch für volatile und const volatile Überladungen schreiben, aber diese sind vergleichsweise viel seltener als const. Sobald Ausnahmenspezifikationen und Transaktionen Teil des Typsystems werden, müssen wir uns auch um noexcept und die Synchronisierung kümmern, und die resultierende kombinatorische Explosion von Typen wird schwierig sein, ohne eine sehr clevere Sprachunterstützung effektiv zu bewältigen. Aber dieses Beispiel zeigt Ihnen, wie diese Art von Code geschrieben wird, und es ist wahrscheinlich gut genug für Ihre Zwecke.

Die Implementierung sieht hässlich aus, aber sie bietet tatsächlich eine sehr saubere Schnittstelle; gegeben Foo wie Sie oben geschrieben haben, würden Sie MyClass ‚s Callback-Funktionalität wie folgt verwenden:

MyClass test; 
Foo foo; 

foo.d = 4; 
test.SetCallback (foo, &Foo::the_func); 
int result = test.run(); // result = 10 

Der obige Code mit jeder Art arbeiten, die int(int,int,int) eine Methode mit der Signatur hat. Beachten Sie, dass Sie SetCallback aufrufen müssen, bevor Sie run aufrufen, andernfalls erhalten Sie eine std::bad_function_call Ausnahme, da der Rückruf noch nicht definiert worden ist.

Verwandte Themen