2012-05-07 21 views
5

Tengo el siguiente:Especificación de una función miembro como una devolución de llamada en 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; 
}; 

y quiero especificar la función de miembro de ClassB :: Malabares() como la devolución de llamada a ClassB :: _ obj. Sería la forma correcta de hacer que en C++ 11 sea (en el constructor del ClassB):

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

Por lo que entiendo, el compilador hará que un objeto std :: función del código de lambda anteriormente. Entonces, cuando se invoque la devolución de llamada, llamará al miembro std :: function :: operator() y luego invocará ClassB :: Juggle() en lugar de invocar ClassB :: Juggle() directamente. A menos que me equivoque sobre lo que sucede bajo las sábanas, todo parece ser un poco ineficiente. ¿Hay una mejor manera?

+2

Tenga en cuenta que capturar 'this' en una lambda (como en su ejemplo) no funciona bien con Visual Studio 2010. –

Respuesta

6

Solo use std::function si realmente necesita funciones polimórficas. De lo contrario, conviértalo en una plantilla.

Para adaptar una función de miembro a un functor use std::mem_fn y luego bind un objeto al primer argumento, el functor resultante puede servir como su devolución de llamada.

muestra:

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

Este lado-pasos el precio de la función en el costo de ser terriblemente feo.

+0

La sintaxis de bind() siempre me hizo un poco inquietante con el marcador de posición _1, _2, _3, etc. parámetros y qué no. Pensé que ahora que C++ tiene lambdas, bind() era obsoleto. Pero como bind() está fuera de Boost y ahora forma parte del estándar, tal vez estaba equivocado con esa suposición. –

+2

@ArcadioAlivioSincero 'bind' todavía puede ser útil. A veces es más corto también. He actualizado el ejemplo a la función 'de lado 'con un pequeño truco. – pmr

+1

Las devoluciones de llamada suelen ser un buen lugar para usar 'std :: function <>' s para mayor flexibilidad (considerando que una * función * se puede usar para registrar * cualquier tipo * de devolución de llamada, necesita algo uniforme para almacenarla) –

Cuestiones relacionadas