valores todas tipos retornan referencia que punteros programacion por paso parametros las funciones ejemplos con c++ boost delegates callback

c++ - todas - puntero de función sin formato de un método vinculado



tipos de parametros en c++ (4)

Necesito vincular un método en una devolución de llamada a función, excepto que este fragmento no es legal como se discutió en demote-boostfunction-to-a-plain-function-pointer .

¿Cuál es la forma más sencilla de obtener este comportamiento?

struct C { void m(int x) { (void) x; _asm int 3; }}; typedef void (*cb_t)(int); int main() { C c; boost::function<void (int x)> cb = boost::bind(&C::m, &c, _1); cb_t raw_cb = *cb.target<cb_t>(); //null dereference raw_cb(1); return 0; }


Lo tengo trabajando ahora mismo convirtiendo C en un singleton, factorizando C :: m en C :: m_Impl, y declarando C :: m (int) estático que lo reenvía a la instancia singleton. hablar sobre un truco.


Puedes hacer tu propia clase para hacer lo mismo que la función de vinculación boost. Todo lo que la clase tiene que hacer es aceptar el tipo de función y un puntero al objeto que contiene la función. Por ejemplo, este es un retorno de nulo y delegado de param void:

template<typename owner> class VoidDelegate : public IDelegate { public: VoidDelegate(void (owner::*aFunc)(void), owner* aOwner) { mFunction = aFunc; mOwner = aOwner; } ~VoidDelegate(void) {} void Invoke(void) { if(mFunction != 0) { (mOwner->*mFunction)(); } } private: void (owner::*mFunction)(void); owner* mOwner; };

Uso:

class C { void CallMe(void) { std::cout << "called"; } }; int main(int aArgc, char** aArgv) { C c; VoidDelegate<C> delegate(&C::CallMe, &c); delegate.Invoke(); }

Ahora, dado que VoidDelegate<C> es un tipo, tener una colección de estos podría no ser práctico, porque ¿qué VoidDelegate<C> si la lista fuera a contener también funciones de la clase B? No pudo.

Aquí es donde el polimorfismo entra en juego. Puede crear una interfaz IDelegate, que tiene una función Invocar:

class IDelegate { virtual ~IDelegate(void) { } virtual void Invoke(void) = 0; }

Si VoidDelegate<T> implementa IDelegate, podría tener una colección de IDelegates y, por lo tanto, tener devoluciones de llamadas a métodos en diferentes tipos de clases.


O puede insertar ese parámetro vinculado en una variable global y crear una función estática que pueda recoger el valor y llamar a la función, o tendrá que generar funciones por instancia sobre la marcha, esto implicará algunas tipo de código-gen sobre la marcha para generar una función de código auxiliar en el montón que tiene una variable local estática establecida en el valor que desea, y luego llama a la función en él.

La primera forma es simple y fácil de entender, pero no es seguro para subprocesos o reentrante. La segunda versión es desordenada y difícil, pero segura para subprocesos y reentrante si se hace correctamente.

Editar: Acabo de descubrir que ATL utiliza la técnica de generación de código para hacer exactamente esto: generan thunks sobre la marcha que configuran this puntero y otros datos y luego saltan a la función de devolución de llamada. Aquí hay un artículo de CodeProject que explica cómo funciona y podría darle una idea de cómo hacerlo usted mismo. En particular, observe la última muestra (Programa 77).

Tenga en cuenta que, dado que el artículo fue escrito, DEP ha entrado en vigencia y deberá usar VirtualAlloc con PAGE_EXECUTE_READWRITE para obtener un trozo de memoria donde pueda asignar sus procesos y ejecutarlos.


#include <iostream> typedef void(*callback_t)(int); template< typename Class, void (Class::*Method_Pointer)(void) > void wrapper( int class_pointer ) { Class * const self = (Class*)(void*)class_pointer; (self->*Method_Pointer)(); } class A { public: int m_i; void callback( ) { std::cout << "callback: " << m_i << std::endl; } }; int main() { A a = { 10 }; callback_t cb = &wrapper<A,&A::callback>; cb( (int)(void*)&a); }