2010-04-29 12 views
6

Angenommen, ich habe eine boost :: -Funktion von mit einer beliebigen Signatur namens CallbackType.Ist es möglich, boost :: bind zu verwenden, um Funktionen effektiv zu verketten?

  • Ist es möglich, boost::bind zu verwenden, um eine Funktion zu schreiben, die die gleichen Argumente wie die CallbackType nimmt, fordert jedoch die beiden functors nacheinander?

Ich bin offen für jede mögliche Lösung, aber hier ist ein ...

... Hypothetisches Beispiel mit einigen magic Vorlage:

Template<typename CallbackType> 
class MyClass 
{ 
    public: 
     CallbackType doBoth; 

     MyClass(CallbackType callback) 
     { 
      doBoth = bind(magic<CallbackType>, 
          protect(bind(&MyClass::alert, this)), 
           protect(callback)     ); 
     } 

     void alert() 
     { 
      cout << "It has been called\n"; 
     } 
}; 

void doIt(int a, int b, int c) 
{ 
    cout << "Doing it!" << a << b << c << "\n"; 
} 

int main() 
{ 
    typedef boost::function<void (int, int, int)> CallbackType; 

    MyClass<CallbackType> object(boost::bind(doIt)); 

    object.doBoth(); 

    return 0; 
} 
+0

Soll 'magic' im Sinne von' bind' implementiert werden? Welche Rolle soll 'bind' spielen? Sicherlich binden Sie nichts an den Rückruf. – Potatoswatter

+0

"magic" wäre vielleicht eine Vorlage, die automatisch einen Funktor erstellt, der zwei Funktoren als Argumente akzeptiert + alle Argumente von 'CallbackType' ... aber das soll nur mein Ziel verdeutlichen, nicht unbedingt eine realistische Lösung bieten. Ich bin offen für drastisch andere Vorschläge. – Catskul

+0

Versuchen Sie ein 'void (void)' mit 'void (int, int, int)' zu erstellen? Oder war das nur ein Tippfehler? – MSN

Antwort

8

Boost bietet bereits eine Möglichkeit, eine Abfolge gebundener Funktionen zu erstellen. Verwenden Sie Lambda's comma operator.

using namespace boost::lambda; 
MyClass mc; 
CallbackType object = (bind(&MyClass::alert, mc), bind(doIt, _1, _2, _3)); 
object(1, 2, 3); 

, dass eine neue Funktors schaffen, object. Wenn Sie diesen Funktor mit drei Argumenten aufrufen, ruft er wiederum mc.alert() auf, bevor diese Argumente an doIt übergeben werden. Die Klammern sind wichtig.

Für mein Beispiel oben zu funktionieren, benötigen Sie alert, um eine const Funktion zu sein. Wenn es nicht-const sein muss, übergeben Sie entweder einen Zeiger an mc, oder wickeln Sie es mit boost::ref(mc). Und Sie müssen Boost.Lambda's bind statt Boost.Bind verwenden; Letzteres ist nicht kompatibel mit Lambdas Funktionskombinationsoperatoren (insbesondere Komma).

+0

Wie würde das mit C++ 11 'std :: bind 'funktionieren? – Valerij

1
template< class Callback > 
struct pre_caller { 
    Callback c; 

    pre_caller(Callback in_c) : c(in_c) {} 

    void alert() {} // or an instance of a functor 

    operator() 
    { alert(); c(); } 

    template< class T1 > 
    operator(T1 a) // not sure if/what qualification to add to a 
    { alert(); c(a); } // or whether to attempt to obtain from 
         // function_traits<Callback>? 
    template< class T1, class T2 > 
    operator(T1 a, T2 b) 
    { alert(); c(a, b); } 

    template< class T1, class T2, class T3 > 
    operator(T1 a, T2 b, T3 c) 
    { alert(); c(a, b, c); } 

    // ad nauseam... and I mean nausea, maybe read up on Boost Preprocessor. 
}; 

Boost-Bind verwendet ein eine Menge Präprozessor-Hacking für seinen variadischen Voodoo, und leider glaube ich nicht, dass es ein Muster oder Werkzeuge für das Head-Patching bietet, was im Wesentlichen das ist.

+0

Es scheint, als sollte es einen einfacheren Weg geben, und vielleicht geht mein Strohmann-Beispiel in die falsche Richtung. Ein Kopfgeld beginnen, aber dies kann als Antwort markiert werden. – Catskul

Verwandte Themen