Pregunta

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

Para aclarar, el siguiente código de ejemplo provoca el Error de compilador 3374:

#include <boost/bind.hpp>

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

    void OnSomeEvent(void)
    {
    }
};
¿Fue útil?

Solución

Si bien su respuesta funciona, expone parte de su implementación al mundo (Managed :: OnSomeEvent). Si no desea que las personas puedan generar el evento OnChange willy-nilly invocando OnSomeEvent (), puede actualizar su clase Managed de la siguiente manera (basado en este consejo ):

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();
}

Tenga en cuenta el formulario alternativo bind<R>() que se utiliza.

Otros consejos

Después de buscar en Google un poco más, finalmente encontré un bonita publicación de blog sobre cómo hacer esto. El código en esa publicación era un poco más de lo que necesitaba, pero la pepita principal era usar una función libre global que tomara un argumento del manejado este puntero envuelto en un gcroot & Lt; & Gt; modelo. Consulte el SomeEventProxy (...) en el código a continuación para ver un ejemplo. Esta función se da 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;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top