significado c++ c functor

c++ - significado - pasar el functor como puntero de función



functor prolog (10)

Intento utilizar una biblioteca de C en una aplicación de C ++ y me he encontrado en la siguiente situación (conozco mi C, pero soy bastante nuevo en C ++). En el lado C, tengo una colección de funciones que toma un puntero a la función como argumento. En el lado de C ++, tengo objetos con un funtor que tiene la misma firma que el puntero de función que necesita la función C. ¿Hay alguna forma de utilizar el functor de C ++ como un puntero de función para pasar a la función C?


Depende si este es un método estático o de instancia, si es estático, puede pasar a través de la función como className :: functionName; si es un método de instancia, es justo más complicado, porque obviamente necesita vincularse a una determinada instancia. pero no puede hacerlo de la misma manera que lo haría con los delegados en C #, etc.

La mejor manera que he encontrado de hacer esto es crear una clase de retención que se crea una instancia con la instancia del objeto, así como el puntero de función, la clase de retención puede invocar la función directamente.


Diría que no, porque un functor C ++ tiene un operador sobrecargado () que es una función miembro , y por lo tanto requeriría un puntero de función miembro. Este es un tipo de datos totalmente diferente de un puntero de función C normal, ya que no se puede invocar sin una instancia de la clase. Tendría que pasar una función normal o una función miembro estática a la biblioteca C. Como un operador sobrecargado () no puede ser estático, no puede hacerlo. Tendría que pasarle a la biblioteca C una función normal, función no miembro o función miembro estática, desde la cual puede invocar el functor C ++.


Encontré esta " gem " usando google. Aparentemente posible, pero seguro que no lo recomendaría. link directo al código fuente de ejemplo.


GCC le permite convertir punteros de función miembro a punteros de función simple (el primer argumento de la función llamada por el puntero de función simple es this ).

Consulte el enlace respectivo en el manual .

Esto requiere el -Wno-pmf-conversions para silenciar la advertencia respectiva para la característica decididamente no estándar. Muy conveniente para interconectar bibliotecas de estilo C con programación de estilo C ++. Cuando el puntero de la función miembro es una constante, esto ni siquiera necesita generar ningún código: la API usaría ese orden de argumento de todos modos.

Si ya tiene un funtor, aplanar el funtor de esa manera probablemente signifique aplanar su operator() , proporcionándole una función que debe llamarse con un puntero de clase funtor como su primer argumento. Lo cual no necesariamente ayuda mucho, pero al menos tiene un enlace C.

Pero al menos cuando no está pasando por funtores esto es útil y proporciona un reemplazo de enlace C sin sentido para std::mem_fn de <functional> .


Hm, tal vez podrías escribir una función de plantilla gratuita que envuelva tus objetos funcionales. Si todos tienen la misma firma, esto debería funcionar. Me gusta esto (no probado):

template<class T> int function_wrapper(int a, int b) { T function_object_instance; return funcion_object_instance( a, b ); }

Esto serviría para todas las funciones que toman dos ints y devuelven un int.


La función de devolución de llamada de CA escrita en C ++ debe declararse como una función extern "C" , por lo que el uso de un functor está directamente fuera. Tendrá que escribir algún tipo de función de envoltura para usar como devolución de llamada y hacer que ese envoltorio llame al funtor. Por supuesto, el protocolo de devolución de llamada deberá tener alguna forma de pasar el contexto a la función para que pueda llegar al functor, o la tarea se vuelve bastante complicada. La mayoría de los esquemas de devolución de llamada tienen una forma de pasar el contexto, pero he trabajado con algunos de muerte cerebral que no lo hacen.

Vea esta respuesta para más detalles (y mire en los comentarios la evidencia anecdótica de que la devolución de llamada debe ser extern "C" y no solo una función de miembro estático):


Muchas API C que toman devoluciones de llamada de puntero a función tienen un parámetro void * para el estado de usuario. Si tiene uno de esos, tiene suerte: puede usar una función exterm C que trate los datos del usuario como un tipo de referencia o clave para buscar el administrador y luego ejecútelo.

De otra manera no.


No creo que puedas: operator() en un objeto de función es realmente una función miembro, y C no sabe nada sobre eso.

Lo que debería poder usar son funciones C ++ gratuitas o funciones estáticas de clases.


No por supuesto. La firma de su función C toma un argumento como función.

void f(void (*func)()) { func(); // Only void f1(), void F2(), .... }

Todos los trucos con functors son usados ​​por funciones de plantilla :

template<class Func> void f (Func func) { func(); // Any functor }


No se puede pasar directamente un puntero a un objeto functor de C ++ como un puntero de función al código C (o incluso al código C ++).

Además, para pasar de forma portátil una devolución de llamada al código C, debe declararse al menos como una función extern "C" no miembro de extern "C" . Al menos, porque algunas API requieren convenciones de llamadas a funciones específicas y, por lo tanto, modificadores de declaración adicionales.

En muchos entornos, C y C ++ tienen las mismas convenciones de llamadas y difieren solo en la creación de nombres, por lo que cualquier función global o miembro estático funcionará. Pero aún necesita envolver la llamada al operator() en una función normal.

  • Si su functor no tiene estado (es un objeto solo para satisfacer algunos requisitos formales, etc.):

    class MyFunctor { // no state public: MyFunctor(); int operator()(SomeType &param) const; }

    puede escribir una función externa normal "C" que crea el functor y ejecuta su operador ().

    extern "C" int MyFunctorInC(SomeType *param) { static MyFunctor my_functor; return my_functor(*param); }

  • Si su functor tiene estado, por ejemplo:

    class MyFunctor { // Some fields here; public: MyFunctor(/* some parameters to set state */); int operator()(SomeType &param) const; // + some methods to retrieve result. }

    y la función de devolución de llamada C toma algún tipo de parámetro de estado de usuario (normalmente nulo *):

    void MyAlgorithmInC(SomeType *arr, int (*fun)(SomeType *, void *), void *user_state);

    puede escribir una función extern normal "C" que arroja su parámetro de estado a su objeto functor:

    extern "C" int MyFunctorInC(SomeType *param, void *user_state) { MyFunctor *my_functor = (MyFunctor *)user_state; return (*my_functor)(*param); }

    y úsalo así:

    MyFunctor my_functor(/* setup parameters */); MyAlgorithmInC(input_data, MyFunctorInC, &my_functor);

  • De lo contrario, la única forma normal de hacerlo (normal como en "sin generar código de máquina en tiempo de ejecución", etc.) es utilizar algo de almacenamiento estático (global) o de subproceso local para pasar el funtor a una función externa "C". Esto limita lo que puede hacer con su código y es feo, pero funcionará.