2012-09-09 17 views
26

Ho una funzione vuota all'interno di una classe. Nel vecchio C++ avrei fatto una funzione statica prendendo il nome della classe come parametro e avevo una mia classe che prendeva una funzione void statica + un void * per chiamarla facilmente.C++ 11 callback in stile?

Tuttavia che si sente vecchia scuola. Inoltre non è un modello che sembra che potrei fare di più. Che cosa è un modo più moderno di creazione di callback per myclassVar.voidReturnVoidParamFunc

+0

"Inoltre, non è templato che si sente come ho potuto fare di più" Il codice C++ non deve essere configurato come C++. –

+0

@NicolBolas ad essere onesti questa soluzione ha fatto utilizzare un unico e funziona * davvero * bene (lambda) –

risposta

53

Usa std::function and lambdas (or std::bind()) per memorizzare oggetti chiamabili:

#include <functional> 
#include <iostream> 


class Test 
{ 
public: 
     void blah() { std::cout << "BLAH!" << std::endl; } 
}; 

class Bim 
{ 
public: 
     void operator()(){ std::cout << "BIM!" << std::endl; } 
}; 

void boum() { std::cout << "BOUM!" << std::endl; } 


int main() 
{ 
    // store the member function of an object: 
    Test test; 
    std::function< void() > callback = std::bind(&Test::blah, test); 
    callback(); 

    // store a callable object (by copy) 
    callback = Bim{}; 
    callback(); 

    // store the address of a static function 
    callback = &boum; 
    callback(); 

    // store a copy of a lambda (that is a callable object) 
    callback = [&]{ test.blah(); }; // often clearer -and not more expensive- than std::bind() 
    callback(); 
}  

Risultato:

BLAH!

BIM!

BOUM!

BLAH!

compila e gestita: http://ideone.com/T6wVp

std::function può essere utilizzato come un qualsiasi oggetto copyiable, quindi sentitevi liberi di memorizzare da qualche parte come un callback, come negli Stati dell'oggetto. Significa anche che puoi metterlo liberamente in contenitori standard, come std::vector< std::function< void() > >.

Si noti inoltre che equivale boost::function and boost::bind sono stati disponibili per anni.

+1

@Hauleth non ho detto è complicato, l'ho detto più chiaro con un lambda. Ricordare l'ordine degli argomenti (in particolare quando si ottiene un oscuro errore di compilazione se è l'ordine sbagliato) lo rende "più difficile" rispetto alla semplice scrittura della chiamata esplicitamente come nel lambda. – Klaim

+1

Suvati per il suono FX! – Ignorant

+0

So che l'hai postato molto tempo fa, ma ho bisogno di qualche chiarimento qui: le prime 3 righe in main dove si associa l'istanza di classe come argomento alla funzione di classe stessa funziona perché il compilatore lo farebbe anche segretamente quando normalmente chiamiamo una funzione membro della classe, giusto? Quindi il compilatore aggiunge un riferimento all'istanza come argomento * this * a ciascuna funzione come primo parametro! Puoi confermare la mia ipotesi? – binaryguy

5

Per un esempio di passaggio dei parametri ad un C++ 11 richiamata utilizzando Lambda e di un vettore, vedere http://ideone.com/tcBCeO o al di sotto:

class Test 
{ 
public: 
     Test (int testType) : m_testType(testType) {}; 
     void blah() { std::cout << "BLAH! " << m_testType << std::endl; } 
     void blahWithParmeter(std::string p) { std::cout << "BLAH1! Parameter=" << p << std::endl; } 
     void blahWithParmeter2(std::string p) { std::cout << "BLAH2! Parameter=" << p << std::endl; } 

     private: 
     int m_testType; 

}; 

class Bim 
{ 
public: 
     void operator()(){ std::cout << "BIM!" << std::endl; } 
}; 

void boum() { std::cout << "BOUM!" << std::endl; } 


int main() 
{ 
    // store the member function of an object: 
    Test test(7); 
    //std::function< void() > callback = std::bind(&Test::blah, test); 
    std::function< void() > callback = std::bind(&Test::blah, test); 
    callback(); 

    // store a callable object (by copy) 
    callback = Bim{}; 
    callback(); 

    // store the address of a static function 
    callback = &boum; 
    callback(); 

    // store a copy of a lambda (that is a callable object) 
    callback = [&]{ test.blah(); }; // might be clearer than calling std::bind() 
    callback(); 

    // example of callback with parameter using a vector 
    typedef std::function<void(std::string&)> TstringCallback; 

    std::vector <TstringCallback> callbackListStringParms; 
    callbackListStringParms.push_back([&] (const std::string& tag) {  test.blahWithParmeter(tag); }); 
    callbackListStringParms.push_back([&] (const std::string& tag) { test.blahWithParmeter2(tag); }); 

    std::string parm1 = "parm1"; 
    std::string parm2 = "parm2"; 
    int i = 0; 
    for (auto cb : callbackListStringParms) 
    { 
     ++i; 
     if (i == 1) 
      cb(parm1); 
     else 
      cb(parm2); 

    } 
}