¿Cómo puedo pasar una función miembro donde se espera una función gratuita?

La pregunta es la siguiente: considere esta pieza de código:

#include  class aClass { public: void aTest(int a, int b) { printf("%d + %d = %d", a, b, a + b); } }; void function1(void (*function)(int, int)) { function(1, 1); } void test(int a,int b) { printf("%d - %d = %d", a , b , a - b); } int main (int argc, const char* argv[]) { aClass a(); function1(&test); function1(&aClass::aTest); // <-- How should I point to a's aClass::test function? return 0; } 

¿Cómo puedo usar la aClass::test como argumento para function1 ? Estoy atrapado en hacer esto.

Me gustaría acceder a un miembro de la clase.

    No hay nada de malo con el uso de punteros a funciones. Sin embargo, los punteros a funciones de miembro no estáticas no son como punteros de función normal: las funciones de miembro deben invocarse sobre un objeto que se pasa como un argumento implícito a la función. La firma de su función de miembro arriba es, por lo tanto,

     void (aClass::*)(int, int) 

    en lugar del tipo que intentas usar

     void (*)(int, int) 

    Un enfoque podría consistir en hacer que la función miembro sea static en cuyo caso no requiere que se llame a ningún objeto y puede usarlo con el tipo void (*)(int, int) .

    Si necesita acceder a cualquier miembro no estático de su clase y necesita seguir con los punteros de función, por ejemplo, porque la función es parte de una interfaz C, su mejor opción es pasar siempre un void* a su función tomando punteros de función y llame a su miembro a través de una función de reenvío que obtiene un objeto del void* y luego llama a la función miembro.

    En una interfaz C ++ adecuada, es posible que desee ver cómo su función toma un argumento de plantilla para que los objetos de función usen tipos de clase arbitrarios. Si no se desea usar una interfaz con plantilla, debe usar algo como std::function : puede crear un objeto de función invocable para esto, por ejemplo, usando std::bind() .

    Los enfoques de tipo seguro usando un argumento de plantilla para el tipo de clase o una std::function< ...> adecuada std::function< ...> son preferibles a usar una interfaz void* ya que eliminan el potencial de errores debido a un lanzamiento al tipo incorrecto.

    Para aclarar cómo usar un puntero de función para llamar a una función miembro, aquí hay un ejemplo:

     // the function using the function pointers: void somefunction(void (*fptr)(void*, int, int), void* context) { fptr(context, 17, 42); } void non_member(void*, int i0, int i1) { std::cout < < "I don't need any context! i0=" << i0 << " i1=" << i1 << "\n"; } struct foo { void member(int i0, int i1) { std::cout << "member function: this=" << this << " i0=" << i0 << " i1=" << i1 << "\n"; } }; void forwarder(void* context, int i0, int i1) { static_cast(context)->member(i0, i1); } int main() { somefunction(&non_member, 0); foo object; somefunction(&forwarder, &object); } 

    La respuesta de @Pete Becker está bien, pero también puede hacerlo sin pasar la instancia de class como un parámetro explícito para function1 en C ++ 11:

     #include  using namespace std::placeholders; void function1(std::function fun) { fun(1, 1); } int main (int argc, const char * argv[]) { ... aClass a; auto fp = std::bind(&aClass::test, a, _1, _2); function1(fp); return 0; } 

    Un puntero a la función miembro es diferente de un puntero a función. Para usar una función de miembro a través de un puntero necesita un puntero (obviamente) y un objeto para aplicarlo. Entonces la versión apropiada de function1 sería

     void function1(void (aClass::*function)(int, int), aClass& a) { (a.*function)(1, 1); } 

    y llamarlo:

     aClass a; // note: no parentheses; with parentheses it's a function declaration function1(&aClass::test, a); 

    Desde 2011, si puede cambiar la function1 , hágalo de esta manera:

     #include  #include  using namespace std; class aClass { public: void aTest(int a, int b) { printf("%d + %d = %d", a, b, a + b); } }; template  void function1(Callable f) { f(1, 1); } void test(int a,int b) { printf("%d - %d = %d", a , b , a - b); } int main() { aClass obj; // Free function function1(&test); // Bound member function using namespace std::placeholders; function1(std::bind(&aClass::aTest, obj, _1, _2)); // Lambda function1([&](int a, int b) { obj.aTest(a, b); }); } 

    ( demostración en vivo )

    Observe también que arreglé su definición de objeto roto ( aClass a(); declara una función).

    Puedes dejar de golpearte la cabeza ahora. Aquí está el contenedor para que la función miembro admita funciones existentes que toman funciones simples C como argumentos. thread_local directiva thread_local es la clave aquí.

    http://cpp.sh/9jhk3

     // Example program #include  #include  using namespace std; typedef int FooCooker_ (int); // Existing function extern "C" void cook_10_foo (FooCooker_ FooCooker) { cout < < "Cooking 10 Foo ..." << endl; cout << "FooCooker:" << endl; FooCooker (10); } struct Bar_ { Bar_ (int Foo = 0) : Foo (Foo) {}; int cook (int Foo) { cout << "This Bar got " << this->Foo < < endl; if (this->Foo >= Foo) { this->Foo -= Foo; cout < < Foo << " cooked" << endl; return Foo; } else { cout << "Can't cook " << Foo << endl; return 0; } } int Foo = 0; }; // Each Bar_ object and a member function need to define // their own wrapper with a global thread_local object ptr // to be called as a plain C function. thread_local static Bar_* BarPtr = NULL; static int cook_in_Bar (int Foo) { return BarPtr->cook (Foo); } thread_local static Bar_* Bar2Ptr = NULL; static int cook_in_Bar2 (int Foo) { return Bar2Ptr->cook (Foo); } int main () { BarPtr = new Bar_ (20); cook_10_foo (cook_in_Bar); Bar2Ptr = new Bar_ (40); cook_10_foo (cook_in_Bar2); delete BarPtr; delete Bar2Ptr; return 0; } 

    Comente cualquier problema con este enfoque.

    Otras respuestas no llaman a las funciones C existentes existentes : http://cpp.sh/8exun