Как использовать boost :: bind в C ++ / CLI для привязки члена управляемого класса - PullRequest
11 голосов
/ 02 октября 2008

Я использую boost :: signal в собственном классе C ++, и сейчас я пишу оболочку .NET в C ++ / CLI, чтобы я мог представить собственные обратные вызовы C ++ в качестве событий .NET. Когда я пытаюсь использовать boost :: bind для получения адреса функции-члена моего управляемого класса, я получаю сообщение об ошибке компилятора 3374, в котором говорится, что я не могу взять адрес функции-члена, пока я не создаю экземпляр делегата. Кто-нибудь знает, как связать функцию-член управляемого класса, используя boost :: bind?

Для пояснения следующий пример кода вызывает ошибку компилятора 3374:

#include <boost/bind.hpp>

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

    void OnSomeEvent(void)
    {
    }
};

Ответы [ 2 ]

10 голосов
/ 01 апреля 2009

Пока ваш ответ работает, он раскрывает часть вашей реализации миру (Managed :: OnSomeEvent). Если вы не хотите, чтобы люди могли вызывать событие OnChange, просто вызвав OnSomeEvent (), вы можете обновить свой класс Managed следующим образом (на основании этого совета ):

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

Обратите внимание на используемую альтернативную форму bind<R>().

4 голосов
/ 03 октября 2008

Пройдя еще несколько поисков, я наконец нашел хороший пост в блоге о том, как это сделать. Код в этом посте был немного больше, чем мне было нужно, но основной слепок заключался в использовании глобальной бесплатной функции, которая принимает аргумент управляемого указателя this, заключенного в шаблон gcroot <>. См. SomeEventProxy (...) в приведенном ниже коде для примера. Затем эта функция поворачивается и вызывает управляемого члена, которого я пытался связать. Мое решение появляется ниже для дальнейшего использования.

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