Question

J'utilise boost :: signal dans une classe C ++ native et j'écris maintenant un wrapper .NET en C ++ / CLI afin de pouvoir exposer les rappels C ++ natifs en tant qu'événements .NET. Lorsque j'essaie d'utiliser boost :: bind pour prendre l'adresse d'une fonction membre de ma classe gérée, l'erreur de compilateur 3374 me dit que je ne peux pas prendre l'adresse d'une fonction membre à moins de créer une instance de délégué. Est-ce que quelqu'un sait comment lier une fonction membre d'une classe gérée à l'aide de boost :: bind?

Pour plus de précision, l'exemple de code suivant provoque l'erreur de compilation 3374:

#include <boost/bind.hpp>

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

    void OnSomeEvent(void)
    {
    }
};
Était-ce utile?

La solution

Pendant que votre réponse fonctionne, elle expose une partie de votre implémentation au monde (Managed :: OnSomeEvent). Si vous ne voulez pas que les gens puissent déclencher l'événement OnChange à volonté en appelant OnSomeEvent (), vous pouvez mettre à jour votre classe gérée comme suit (en fonction de ce conseil ):

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

Notez le bind<R>() formulaire alternatif utilisé.

Autres conseils

Après avoir cherché un peu plus sur Google, j'ai finalement trouvé un blog agréable sur la façon de le faire. Le code de ce message était un peu plus que nécessaire, mais le nugget principal consistait à utiliser une fonction libre globale prenant un argument du contrôle de ce pointeur, enveloppé dans un gcroot & Lt; & Gt; modèle. Voir SomeEventProxy (...) dans le code ci-dessous pour un exemple. Cette fonction se retourne ensuite et appelle le membre géré que j'essayais de lier. Ma solution apparaît ci-dessous pour référence future.

#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;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top