Замените собственный обратный вызов свободной функции на функцию-член, используя boost :: bind - PullRequest
0 голосов
/ 31 января 2012

У меня есть собственные классы C ++, обернутые классами C ++ / CLI, чтобы классы C # могли их использовать. Противно, но работает. До сих пор, чтобы сопоставить нативные обратные вызовы с событиями .NET, я делал такие вещи в своих классах-обёртках:

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_dManagedEvent является System::Action^
  • Собственные обратные вызовы определены как свободные функции; в данном случае typedef void __stdcall NativeCallback(); внутри INativeInterface.

Это прекрасно работает, но теперь я влюбился в Boost, что означает использование boost::function и boost::bind. Это прекрасно работает между родными классами, но, скажем, я хочу изменить свой registerEventCallback функция, чтобы он получил boost::function<void()>. Как мне изменить методы add и remove?

Я думал об этом, но это вынуждает меня писать другую функцию-член для каждого события, и я не уверен, что она будет даже построена, потому что this является дескриптором отслеживания:

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

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

Есть ли лучшее решение?

Обновление : В ответе @Ben Voigt я попробовал следующее:

   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.

(строка 61 файла Test.cpp является последней из add метода)

Обновление 2 : При этом он собирается и работает нормально:

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

1 Ответ

2 голосов
/ 02 февраля 2012

Да.То, что у вас уже есть.

GetFunctionPointerForDelegate создает батут, содержащий указатель this, поэтому нет необходимости в boost::bind.

. Единственное, что изменится, вместо передачипростой указатель на функцию, вы передадите функтор boost::function.Преобразование должно быть неявным, ваш код C ++ / CLI не нужно будет менять.

Кроме того, прежде чем вы слишком сильно полюбите Boost, взгляните на класс std::function, у него много новых возможностей сC ++ 11.

...