2012-01-31 144 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