Search code examples
delegatesc++-cliboost-bindboost-signals

How to use boost::bind in C++/CLI to bind a member of a managed class


I am using boost::signal in a native C++ class, and I now I am writing a .NET wrapper in C++/CLI, so that I can expose the native C++ callbacks as .NET events. When I try to use boost::bind to take the address of a member function of my managed class, I get compiler error 3374, saying I cannot take the address of a member function unless I am creating a delegate instance. Does anyone know how to bind a member function of a managed class using boost::bind?

For clarification, the following sample code causes Compiler Error 3374:

#include <boost/bind.hpp>

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

    void OnSomeEvent(void)
    {
    }
};

Solution

  • While your answer works, it exposes some of your implementation to the world (Managed::OnSomeEvent). If you don't want people to be able to raise the OnChange event willy-nilly by invoking OnSomeEvent(), you can update your Managed class as follows (based on this advice):

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

    Note the alternate bind<R>() form that's used.