2012-09-09 10 views
26

Tengo una función de vacío dentro de una clase. En C++ antiguo, creaba una función estática tomando el nombre de la clase como parámetro y tenía mi propia clase que tomaba una función nula estática + un vacío * para que yo la llamara fácilmente.C++ 11 devoluciones de llamada con estilo?

Sin embargo, eso se siente en la vieja escuela. Tampoco es una plantilla que parece que podría estar haciendo más. Lo que es una forma más moderna de crear devoluciones de llamada a myclassVar.voidReturnVoidParamFunc

+0

"Tampoco se templated que se siente como que podría estar haciendo más" El código de C++ no tiene que ser una plantilla para ser C++. –

+0

@NicolBolas para ser justos, esta solución usó una y funciona * realmente * bien (lambdas) –

Respuesta

53

Uso std::function and lambdas (or std::bind()) para almacenar callables:

#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(); 
}  

Resultado:

blah!

BIM!

BOUM!

BLAH!

compila y ejecuta: http://ideone.com/T6wVp

std::function se puede utilizar como cualquier objeto copyiable, por lo que no dude en almacenar en algún lugar como una devolución de llamada, al igual que en el miembro de objeto. También significa que puede colocarlo libremente en contenedores estándar, como std::vector< std::function< void() > >.

También tenga en cuenta que el equivalente boost::function and boost::bind ha estado disponible desde hace años.

+1

@Hauleth No dije que fuera complicado, lo dije más claro con una lambda. Recordar el orden de los argumentos (en particular cuando obtienes un oscuro error de compilación si es el orden incorrecto) lo hace "más difícil" que simplemente escribir la llamada explícitamente como en el lambda. – Klaim

+1

¡Vota al alza por el efecto de sonido! – Ignorant

+0

Sé que publicaste esto hace mucho tiempo, pero necesito algunas aclaraciones aquí: las primeras 3 líneas en main donde enlazas la instancia de clase como argumento para la función de clase en sí misma funciona porque el compilador lo haría también en secreto cuando normalmente llamamos una función de miembro de la clase, ¿verdad? ¡Entonces el compilador agrega una referencia a la instancia como * este * argumento a cada función como primer parámetro! ¿Puedes confirmar mi suposición? – binaryguy

5

Para un ejemplo de pasar en los parámetros a una devolución de llamada C++ 11 usando Lambda de y un vector, ver http://ideone.com/tcBCeO o a continuación:

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); 

    } 
}  
Cuestiones relacionadas