2012-01-31 107 views
0

替换带有成员函数的自由函数原生回调函数我拥有由C++/CLI类包装的本地C++类,以便C#类可以使用它们。讨厌,但工作。到目前为止,映射本地回调来我做了这样的事情在我的包装类.NET事件:使用boost :: bind

void Wrapper::ManagedEvent::add(Action^ managedEventHandler){ 
    m_dManagedEvent += managedEventHandler; 
    m_pNativeInstance->registerEventCallback(static_cast<INativeInterface::NativeCallback*>(
     Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(managedEventHandler).ToPointer())); 
} 

void Wrapper::ManagedEvent::remove(Action^ managedEventHandler){ 
    m_dManagedEvent -= managedEventHandler; 
    m_pNativeInstance->registerEventCallback(NULL); 
} 
  • m_dManagedEventSystem::Action^
  • 本地回调定义为免费的功能;在这种情况下,typedef void __stdcall NativeCallback();,内部INativeInterface

这工作正常,但现在我爱上了Boost,这意味着使用boost::functionboost::bind。这在原生类之间很好,但是假设我想改变我的 registerEventCallback函数,以便它收到boost::function<void()>。我将如何改变addremove方法?

我想到了这一点,但它迫使我写的每个事件的另一个成员函数,我不知道它甚至会因为建设是this跟踪句柄:

void Wrapper::FireManagedEvent(){ 
    m_dManagedEvent(); 
} 

void Wrapper::ManagedEvent::add(Action^ managedEventHandler){ 
     m_dManagedEvent += managedEventHandler; 
     m_pNativeInstance->registerEventCallback(boost::bind(&Wrapper::FireManagedEvent, this)); 
    } 

有没有更好的解决办法?

更新:每@Ben福格特的回答,我试过如下:

void Wrapper::ManagedEvent::add(Action^ managedEventHandler){ 
     m_dManagedEvent += managedEventHandler; 
     m_pNativeInstance->registerEventCallback(static_cast< boost::function< void() > >(
      Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(managedEventHandler).ToPointer())); 
    } 

但它给一个编译器错误:

2>D:\SVN.DRA.WorkingCopy\DRALibraries\Boost_1_48_0\boost/function/function_template.hpp(112): error C2064: term does not evaluate to a function taking 0 arguments 
2>   D:\SVN.DRA.WorkingCopy\DRALibraries\Boost_1_48_0\boost/function/function_template.hpp(110) : while compiling class template member function 'void boost::detail::function::void_function_invoker0<FunctionPtr,R>::invoke(boost::detail::function::function_buffer &)' 
2>   with 
2>   [ 
2>    FunctionPtr=void *, 
2>    R=void 
2>   ] 
2>   D:\SVN.DRA.WorkingCopy\DRALibraries\Boost_1_48_0\boost/function/function_template.hpp(907) : see reference to class template instantiation 'boost::detail::function::void_function_invoker0<FunctionPtr,R>' being compiled 
2>   with 
2>   [ 
2>    FunctionPtr=void *, 
2>    R=void 
2>   ] 
2>   D:\SVN.DRA.WorkingCopy\DRALibraries\Boost_1_48_0\boost/function/function_template.hpp(722) : see reference to function template instantiation 'void boost::function0<R>::assign_to<Functor>(Functor)' being compiled 
2>   with 
2>   [ 
2>    R=void, 
2>    Functor=void * 
2>   ] 
2>   D:\SVN.DRA.WorkingCopy\DRALibraries\Boost_1_48_0\boost/function/function_template.hpp(1043) : see reference to function template instantiation 'boost::function0<R>::function0<void*>(Functor,int)' being compiled 
2>   with 
2>   [ 
2>    R=void, 
2>    Functor=void * 
2>   ] 
2>   Test.cpp(61) : see reference to function template instantiation 'boost::function<Signature>::function<void*>(Functor,int)' being compiled 
2>   with 
2>   [ 
2>    Signature=void (void), 
2>    Functor=void * 
2>   ] 
2> 
2>Build FAILED. 

(线Test.cpp的61是最后一个方法之一add

更新2:这样做,它建立和运行OK:

void Wrapper::ManagedEvent::add(Action^ managedEventHandler){ 
    m_dManagedEvent += managedEventHandler; 
    void(__stdcall*pTrampoline)() = static_cast<void(__stdcall*)()>(Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(managedEventHandler).ToPointer()); 
    m_pNativeInstance->registerEventCallback(boost::function<void()>(pTrampoline)); 
} 

回答

2

是的。你已经拥有了什么。

GetFunctionPointerForDelegate创建一个包含this指针的蹦床,因此不需要boost::bind

唯一会改变的不是传递一个普通的函数指针,而是传递一个boost::function仿函数。转换应该是隐含的,你的C++/CLI代码不需要改变。

另外,在你爱上Boost之前,看看std::function这个类,它有很多C++ 11的新功能。

+0

它不编译,看我更新的问题。我也尝试过'reinterpret_cast'并得到了一个不同的错误。 – 2012-02-10 12:51:09

+0

我修正了它,看起来像一个调用约定的事情:它看起来像C++/CLI在默认情况下使用__cdecl,并且涉及__stdcall的显式强制转换是必要的。查看问题的最后更新。现在它编译并正常工作。请告诉我,如果有更优雅的方式,或者我没有注意到的一些陷阱。 – 2012-02-10 13:05:02

+1

@dario:我不确定,但我认为你需要使用'__cdecl'来兼容'std :: function'和'boost :: function'。通过在托管代理类型上指定“CallingConvention :: Cdecl”,可以使'GetFunctionPointerForDelegate'返回'void(__ cdecl *)()'。 – 2012-02-10 13:17:52