11 Stimmen

Wie verwendet man boost::bind in C++/CLI, um ein Mitglied einer verwalteten Klasse zu binden?

Ich verwende boost::signal in einer nativen C++-Klasse, und ich schreibe jetzt einen .NET-Wrapper in C++/CLI, damit ich die nativen C++-Callbacks als .NET-Ereignisse darstellen kann. Wenn ich versuche, boost::bind zu verwenden, um die Adresse einer Mitgliedsfunktion meiner verwalteten Klasse zu übernehmen, erhalte ich den Compilerfehler 3374, der besagt, dass ich die Adresse einer Mitgliedsfunktion nur übernehmen kann, wenn ich eine Delegateninstanz erstelle. Weiß jemand, wie man eine Mitgliedsfunktion einer verwalteten Klasse mit boost::bind binden kann?

Zur Verdeutlichung: Der folgende Beispielcode verursacht den Compilerfehler 3374:

#include <boost/bind.hpp>

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

    void OnSomeEvent(void)
    {
    }
};

10voto

yagni Punkte 1080

Ihre Antwort funktioniert zwar, aber sie macht einen Teil Ihrer Implementierung für die Welt sichtbar (Managed::OnSomeEvent). Wenn Sie nicht wollen, dass andere das OnChange-Ereignis willkürlich durch den Aufruf von OnSomeEvent() auslösen können, können Sie Ihre Managed-Klasse wie folgt aktualisieren (basierend auf dieser Rat ):

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

Beachten Sie den alternativen bind<R>() Form, die verwendet wird.

0 Stimmen

Ich versuche, hier etwas Ähnliches zu tun. Irgendwelche Ratschläge für die Übergabe von Zeichenfolgen an/von den Rückruf? stackoverflow.com/q/42304020/15369

4voto

Brian Stewart Punkte 8870

Nachdem ich weiter gegoogelt hatte, fand ich schließlich eine schöner Blogbeitrag darüber, wie dies zu tun ist. Der Code in diesem Beitrag war ein wenig mehr, als ich brauchte, aber der wichtigste Punkt war die Verwendung einer globalen free-Funktion, die ein Argument des verwalteten this-Zeigers in einer gcroot<>-Schablone enthält. Siehe die SomeEventProxy(...) im untenstehenden Code als Beispiel. Diese Funktion dreht sich dann um und ruft das verwaltete Mitglied auf, das ich zu binden versuchte. Meine Lösung erscheint unten für zukünftige Referenz.

#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;
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X