resueltos punteros puntero parametros funciones ejercicios declaracion como cadenas aritmetica c++ c pointers function-pointers

c++ - parametros - punteros en c



Convierta el puntero de la función C++ al puntero de la función c (7)

¡La respuesta de @Snps es perfecta! Pero como @DXM mencionado puede contener solo una devolución de llamada. Lo he mejorado un poco, ahora puede mantener muchas devoluciones de llamadas del mismo tipo. Es un poco extraño, pero funciona perfecto:

#include <type_traits> template<typename T> struct ActualType { typedef T type; }; template<typename T> struct ActualType<T*> { typedef typename ActualType<T>::type type; }; template<typename T, unsigned int n,typename CallerType> struct Callback; template<typename Ret, typename ... Params, unsigned int n,typename CallerType> struct Callback<Ret(Params...), n,CallerType> { typedef Ret (*ret_cb)(Params...); template<typename ... Args> static Ret callback(Args ... args) { func(args...); } static ret_cb getCallback(std::function<Ret(Params...)> fn) { func = fn; return static_cast<ret_cb>(Callback<Ret(Params...), n,CallerType>::callback); } static std::function<Ret(Params...)> func; }; template<typename Ret, typename ... Params, unsigned int n,typename CallerType> std::function<Ret(Params...)> Callback<Ret(Params...), n,CallerType>::func; #define GETCB(ptrtype,callertype) Callback<ActualType<ptrtype>::type,__COUNTER__,callertype>::getCallback

Ahora puedes hacer algo como esto:

typedef void (cb_type)(uint8_t, uint8_t); class testfunc { public: void test(int x) { std::cout << "in testfunc.test " <<x<< std::endl; } void test1(int x) { std::cout << "in testfunc.test1 " <<x<< std::endl; } }; cb_type* f = GETCB(cb_type, testfunc)(std::bind(&testfunc::test, tf, std::placeholders::_2)); cb_type* f1 = GETCB(cb_type, testfunc)( std::bind(&testfunc::test1, tf, std::placeholders::_2)); f(5, 4); f1(5, 7);

Estoy desarrollando una aplicación C ++ usando una biblioteca C. Tengo que enviar un puntero para funcionar en la biblioteca C.

Esta es mi clase:

class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); private: Ui::MainWindow *ui; void f(int*); private slots: void on_btn_clicked(); };

Esta es mi función on_btn_clicked:

void MainWindow::on_btn_clicked() { void (MainWindow::* ptfptr) (int*) = &MainWindow::f; c_library_function(static_cast<void()(int*)>(ptfptr), NULL); }

La función C debe tener un puntero a una de esas funciones: void f (int *). Pero el código anterior no funciona, no puedo convertir mi función miembro en el puntero deseado.

¿Alguien puede ayudarme?


La respuesta corta es: puede convertir un puntero de función miembro a un puntero de función C normal usando std :: mem_fn .

Esa es la respuesta dada a la pregunta, pero esta pregunta parece tener una premisa confusa, ya que el solicitante espera que el código C pueda llamar a un método de instancia de MainWindow sin tener una ventana principal *, lo cual es simplemente imposible.

Si usa mem_fn para convertir MainWindow::on_btn_clicked a un puntero de función C, entonces todavía tiene una función que toma una MainWindow* como su primer argumento.

void (*window_callback)(MainWindow*,int*) = std::mem_fn(&MainWindow::on_btn_clicked);

Esa es la respuesta a la pregunta tal como se dio, pero no coincide con la interfaz. Tendría que escribir una función C para envolver la llamada a una instancia específica (después de todo, su código C API no sabe nada acerca de MainWindow o cualquier instancia específica de la misma):

void window_button_click_wrapper(int* arg) { MainWindow::inst()->on_btn_clicked(arg); }

Esto se considera un anti-patrón OO, pero como la API C no sabe nada sobre su objeto, es la única forma.


La respuesta de @Snps es genial. Lo extendí con una función de creador que crea una devolución de llamada, ya que siempre uso devoluciones de llamada sin parámetros:

typedef void (*voidCCallback)(); template<typename T> voidCCallback makeCCallback(void (T::*method)(),T* r){ Callback<void()>::func = std::bind(method, r); void (*c_function_pointer)() = static_cast<decltype(c_function_pointer)>(Callback<void()>::callback); return c_function_pointer; }

A partir de ese momento, puede crear su devolución de llamada C simple desde dentro de la clase o en cualquier otro lugar y hacer que el miembro se llame:

voidCCallback callback = makeCCallback(&Foo::print, this); plainOldCFunction(callback);


No puede pasar un puntero de función a una función miembro no estática. Lo que puede hacer es crear una función estática o global que realice la llamada con un parámetro de instancia.

Aquí hay un ejemplo que considero útil que utiliza una clase auxiliar con dos miembros: un contenedor de funciones y una función de devolución de llamada que llama al contenedor.

template <typename T> struct Callback; template <typename Ret, typename... Params> struct Callback<Ret(Params...)> { template <typename... Args> static Ret callback(Args... args) { return func(args...); } static std::function<Ret(Params...)> func; }; // Initialize the static member. template <typename Ret, typename... Params> std::function<Ret(Params...)> Callback<Ret(Params...)>::func;

Al usar esto, puede almacenar cualquier función de miembro invocable, incluso no estática (usando std::bind ) y convertirla en un puntero c usando la función Callback::callback . P.ej:

struct Foo { void print(int* x) { // Some member function. std::cout << *x << std::endl; } }; int main() { Foo foo; // Create instance of Foo. // Store member function and the instance using std::bind. Callback<void(int*)>::func = std::bind(&Foo::print, foo, std::placeholders::_1); // Convert callback-function to c-pointer. void (*c_func)(int*) = static_cast<decltype(c_func)>(Callback<void(int*)>::callback); // Use in any way you wish. std::unique_ptr<int> iptr{new int(5)}; c_func(iptr.get()); }


No puede pasar un puntero de función miembro no estático como un puntero de función normal. No son lo mismo, y probablemente ni siquiera sean del mismo tamaño.

Sin embargo, normalmente puede pasar un puntero a una función miembro estática a través de C. Por lo general, al registrar una devolución de llamada en una API C, también puede pasar un puntero de "datos de usuario" que se devuelve a su función registrada. Entonces puedes hacer algo como:

class MyClass { void non_static_func(/* args */); public: static void static_func(MyClass *ptr, /* other args */) { ptr->non_static_func(/* other args */); } };

Luego registre su devolución de llamada como

c_library_function(MyClass::static_func, this);

es decir, pasar el puntero de instancia al método estático y usarlo como una función de reenvío.

Estrictamente hablando para la portabilidad total, necesitas usar una función gratuita declarada extern "C" lugar de un miembro estático para hacer tu reenvío (declarado como friend si es necesario), pero prácticamente nunca he tenido ningún problema al usar este método para la interfaz Código C ++ con código GObject, que es C callback-heavy.


Si lo recuerdo correctamente, solo se puede acceder a los métodos estáticos de una clase mediante el puntero C "normal" a la sintaxis de la función. Intenta hacerlo estático. El puntero a un método de una clase necesita información adicional, como el "objeto" (esto) que no tiene ningún significado para un método C puro.

Las preguntas frecuentes que se muestran aquí tienen una buena explicación y una posible solución (fea) para su problema.


Tengo una idea (no totalmente compatible con estándares, ya que falta la extern "C" ):

class MainWindow; static MainWindow* instance; class MainWindow { public: MainWindow() { instance = this; registerCallback([](int* arg){instance->...}); } };

Tendrá problemas si se instancian instancias múltiples de MainWindow .