Domanda

Sto usando boost :: signal in una classe C ++ nativa e ora sto scrivendo un wrapper .NET in C ++ / CLI, in modo da poter esporre i callback C ++ nativi come eventi .NET. Quando provo ad usare boost :: bind per prendere l'indirizzo di una funzione membro della mia classe gestita, ottengo l'errore del compilatore 3374, dicendo che non posso prendere l'indirizzo di una funzione membro a meno che non stia creando un'istanza delegata. Qualcuno sa come associare una funzione membro di una classe gestita usando boost :: bind?

Per chiarimenti, il seguente codice di esempio provoca l'errore del compilatore 3374:

#include <boost/bind.hpp>

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

    void OnSomeEvent(void)
    {
    }
};
È stato utile?

Soluzione

Mentre la tua risposta funziona, espone una parte della tua implementazione al mondo (Managed :: OnSomeEvent). Se non vuoi che le persone siano in grado di sollevare l'evento OnChange volenti o nolenti invocando OnSomeEvent (), puoi aggiornare la tua classe Managed come segue (basato su questo consiglio ):

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 il bind<R>() modulo alternativo utilizzato.

Altri suggerimenti

Dopo aver cercato su Google ancora un po ', ho finalmente trovato un bel post sul blog su come farlo. Il codice in quel post era un po 'più di quello di cui avevo bisogno, ma il nugget principale era usare una funzione globale libera che prende un argomento del gestito questo puntatore racchiuso in un gcroot & Lt; & Gt; modello. Vedi SomeEventProxy (...) nel codice qui sotto per un esempio. Questa funzione quindi si gira e chiama il membro gestito che stavo cercando di associare. La mia soluzione appare sotto per riferimento futuro.

#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;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top