2012-05-07 5 views
5

Ho il seguente:Specificare una funzione di membro come un callback in C++ 11

typedef std::function<bool (const std::string&)> SomethingCoolCb; 

class ClassA 
{ 
public: 
    void OnSomethingCool(const SomethingCoolCb& cb) 
    { 
     _cb = cb; 
    } 

private: 
    SomethingCoolCb _cb; 
}; 

class ClassB 
{ 
public: 
    ClassB(); 
    bool Juggle(const std::string& arg); 

private: 
    ClassA _obj; 
}; 

e voglio specificare la funzione di membro ClassB :: Juggle() come callback per ClassB :: _ obj. Sarebbe il modo corretto per farlo in C++ 11 essere (nel costruttore di ClassB):

ClassB::ClassB() 
{ 
    _obj.OnDoSomethingCool(
     [&](const std::string& arg) -> bool 
     { 
      return Juggle(arg); 
     }); 
} 

Da quello che ho capito, il compilatore farà un oggetto std :: funzione di fuori del codice Lambda sopra. Quindi, quando viene richiamato il callback, chiamerà il membro std :: function :: operator() e quindi invocherà ClassB :: Juggle() invece di richiamare direttamente ClassB :: Juggle(). A meno che non mi sbagli su cosa succede sotto le coperte, tutto sembra essere un po 'inefficiente. C'è un modo migliore?

+2

Attenzione che catturare 'this' in una lambda (come nel tuo esempio) non funziona bene con Visual Studio 2010. –

risposta

6

Utilizzare solo std::function se sono realmente necessarie funzioni polimorfiche. Altrimenti rendilo un modello.

Per adattare una funzione membro a un functor utilizzare std::mem_fn e quindi bind un oggetto al primo argomento, il functor risultante può fungere da callback.

Esempio:

#include <string> 
#include <functional> 

template<typename F> 
class ClassA 
{ 
public: 
    ClassA(F f) : _cb(f) {} 

private: 
    F _cb; 
}; 

class ClassB 
{ 
public: 
    ClassB() 
    : _obj(std::bind(&ClassB::Juggle, this, 
        std::placeholders::_1)) 
    {} 
    bool Juggle(const std::string& arg) {return true;} 
private: 
    ClassA<decltype(std::bind(
         std::declval<bool (ClassB::*)(const std::string&)>() 
         , std::declval<ClassB*>() 
         , std::placeholders::_1 
        )) > _obj; 
}; 

int main() 
{ 
    ClassB b; 
    return 0; 
} 

Questo lato-passi il costo della funzione a costo di essere terribilmente brutto.

+0

La sintassi bind() mi ha sempre fatto un po 'queezy con il segnaposto _1, _2, _3, ecc. parametri e cosa no Ho capito che ora che C++ ha lambda, bind() era obsoleto. Ma poiché bind() è fuori da Boost e ora fa parte dello standard, forse sono stato scambiato per questa ipotesi. –

+2

@ArcadioAlivioSincero 'bind' può essere ancora utile. A volte è anche più breve. Ho aggiornato l'esempio di side-step 'function' con un piccolo trucco. – pmr

+1

I callback sono in genere un buon posto per usare 'std :: function <>' s per la flessibilità (considerando che una * funzione * può essere usata per registrare * qualsiasi tipo * di callback, hai bisogno di qualcosa di uniforme per salvarlo in) –

Problemi correlati