2008-10-02 22 views
11

Estoy usando boost :: signal en una clase C++ nativa, y ahora estoy escribiendo un contenedor .NET en C++/CLI, para que pueda exponer las devoluciones de C++ nativas como eventos .NET. Cuando trato de usar boost :: bind para tomar la dirección de una función miembro de mi clase administrada, obtengo el error 3374 del compilador, que dice que no puedo tomar la dirección de una función miembro a menos que esté creando una instancia delegada. ¿Alguien sabe cómo vincular una función miembro de una clase administrada usando boost :: bind?Cómo usar boost :: bind en C++/CLI para vincular un miembro de una clase administrada

Para mayor claridad, el código de ejemplo hace que el compilador de error 3374:

#include <boost/bind.hpp> 

public ref class Managed 
{ 
public: 
    Managed() 
    { 
     boost::bind(&Managed::OnSomeEvent, this); 
    } 

    void OnSomeEvent(void) 
    { 
    } 
}; 

Respuesta

10

Mientras su respuesta funciona, expone parte de su implementación al mundo (Managed :: OnSomeEvent). Si usted no quiere que la gente sea capaz de provocar el evento OnChange se quiera o no, invocando OnSomeEvent(), puede actualizar su clase administrada de la siguiente manera (en base a this advice):

public delegate void ChangeHandler(void); 
typedef void (__stdcall *ChangeCallback)(void); 

public ref class Managed 
{ 
public: 
    Managed(Native* Nat); 
    ~Managed(); 

    event ChangeHandler^ OnChange; 

private: 
    void OnSomeEvent(void); 
    Native* native; 
    Callback* callback; 
    GCHandle gch; 
}; 

Managed::Managed(Native* Nat) 
: native(Nat) 
{ 
    callback = new Callback; 

    ChangeHandler^ handler = gcnew ChangeHandler(this, &Managed::OnSomeEvent); 
    gch = GCHandle::Alloc(handler); 
    System::IntPtr ip = Marshal::GetFunctionPointerForDelegate(handler); 
    ChangeCallback cbFunc = static_cast<ChangeCallback>(ip.ToPointer()); 

    *callback = native->RegisterCallback(boost::bind<void>(cbFunc)); 
} 

Managed::~Managed() 
{ 
    native->UnregisterCallback(*callback); 
    delete callback; 
    if (gch.IsAllocated) 
    { 
     gch.Free(); 
    } 
} 

void Managed::OnSomeEvent(void) 
{ 
    OnChange(); 
} 

Nota la forma alternativa de bind<R>() eso es usado.

+0

Estoy tratando de hacer algo similar aquí. ¿Algún consejo para pasar cadenas a/desde la devolución de llamada? http://stackoverflow.com/q/42304020/15369 –

4

Tras Google un poco más, finalmente encontré un nice blog post acerca de cómo hacer esto. El código en esa publicación era un poco más de lo que necesitaba, pero el nugget principal era usar una función libre global que toma un argumento del manejado de este puntero envuelto en una plantilla gcroot <>. Consulte el SomeEventProxy (...) en el siguiente código para ver un ejemplo. Esta función da la vuelta y llama al miembro administrado que estaba tratando de vincular. Mi solución aparece a continuación para referencia futura.

#include <msclr/marshal.h> 

#include <boost/bind.hpp> 
#include <boost/signal.hpp> 
#include <iostream> 

#using <mscorlib.dll> 

using namespace System; 
using namespace msclr::interop; 

typedef boost::signal<void (void)> ChangedSignal; 
typedef boost::signal<void (void)>::slot_function_type ChangedSignalCB; 
typedef boost::signals::connection Callback; 


class Native 
{ 
public: 

    void ChangeIt() 
    { 
     changed(); 
    } 

    Callback RegisterCallback(ChangedSignalCB Subscriber) 
    { 
     return changed.connect(Subscriber); 
    } 

    void UnregisterCallback(Callback CB) 
    { 
     changed.disconnect(CB); 
    } 

private: 
    ChangedSignal changed; 
}; 



delegate void ChangeHandler(void); 


public ref class Managed 
{ 
public: 
    Managed(Native* Nat); 
    ~Managed(); 
    void OnSomeEvent(void); 

    event ChangeHandler^ OnChange; 

private: 
    Native* native; 
    Callback* callback; 
}; 


void SomeEventProxy(gcroot<Managed^> This) 
{ 
    This->OnSomeEvent(); 
} 


Managed::Managed(Native* Nat) 
: native(Nat) 
{ 
    native = Nat; 
    callback = new Callback; 
    *callback = native->RegisterCallback(boost::bind(SomeEventProxy, gcroot<Managed^>(this))); 
} 

Managed::~Managed() 
{ 
    native->UnregisterCallback(*callback); 
    delete callback; 
} 

void Managed::OnSomeEvent(void) 
{ 
    OnChange(); 
} 


void OnChanged(void) 
{ 
    Console::WriteLine("Got it!"); 
} 

int main(array<System::String ^> ^args) 
{ 
    Native* native = new Native; 
    Managed^ managed = gcnew Managed(native); 

    managed->OnChange += gcnew ChangeHandler(OnChanged); 

    native->ChangeIt(); 

    delete native; 
    return 0; 
} 
Cuestiones relacionadas