Как привести к нему boost :: bind (& amp; myClass :: fun, this, _1, _2, _3) к typedef void (* fun) (arg1, arg2, arg3)?

В lib Bullet определен тип:

typedef void (*btNearCallback)(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, const btDispatcherInfo& dispatchInfo);

в там документы представлены образец использования (стр. 23):

void MyNearCallback(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, const btDispatcherInfo& dispatchInfo) {
// Do your collision logic here
// Only dispatch the Bullet collision information if you want the physics to continue
dispatcher.defaultNearCallback(collisionPair, dispatcher, dispatchInfo);
}

Я скопировал этот пример кода в класс защиты, чтобы мой класс получил эту функцию, и я буду способен выполнять такие приведения, как:

    dispatcher->setNearCallback(boost::bind(&BulletAPIWrapper::MyNearCallback, this, _1, _2, _3));

вместо C как dispatcher->setNearCallback(MyNearCallback); из учебника Bullet.

Все же мой VS2010 sp1 выдает мне ошибку:

Error   44  error C2664: 'btCollisionDispatcher::setNearCallback' : cannot convert parameter 1 from 'boost::_bi::bind_t<R,F,L>' to 'btNearCallback'

Поэтому мне интересно, как привести в действие boost :: bind для такого typedef?

Возможно ли иметь статическую функцию класса (или хотя бы такую ​​глобальную функцию):

void MyNearCallback(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, const btDispatcherInfo& dispatchInfo, BulletAPI* api) {
}

вызов dispatcher->setNearCallback( boost::bind(MyNearCallback, _1, _2, _3, this));

потому что это приводит к почти той же ошибке для меня:

Error   44  error C2664: 'btCollisionDispatcher::setNearCallback' : cannot convert parameter 1 from 'boost::_bi::bind_t<R,F,L>' to 'btNearCallback'

Я тоже пробовал как описано здесь:

template<unsigned ID,typename Functor>
boost::optional<Functor> &get_local()
{
static boost::optional<Functor> local;
return local;
}

template<unsigned ID,typename Functor>
typename Functor::result_type wrapper(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, const btDispatcherInfo& dispatchInfo)
{
return get_local<ID,Functor>().get()(collisionPair, dispatcher, dispatchInfo);
}

template<typename ReturnType>
struct Func
{
typedef ReturnType (*type)(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, const btDispatcherInfo& dispatchInfo);
};

template<unsigned ID,typename Functor>
typename Func<typename Functor::result_type>::type get_wrapper(Functor f)
{
(get_local<ID,Functor>()) = f;
return wrapper<ID,Functor>;
}

struct NearCallbackWrapper
{
class BulletAPI;
void MyNearCallback(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, const btDispatcherInfo& dispatchInfo) {
std::cout << "called" << std::endl;
}
};

//....
dispatcher->setNearCallback( get_wrapper<0>(  boost::bind(&NearCallbackWrapper::MyNearCallback,this) ) );

все же я получил такую ​​ошибку из этого:

error C2664: 'btCollisionDispatcher::setNearCallback' : cannot convert parameter 1 from 'void (__cdecl *)(btBroadphasePair &,btCollisionDispatcher &,const btDispatcherInfo &)' to 'btNearCallback'

9

Решение

Как вы думаете, почему вы «должны быть в состоянии сыграть как …»? SetNearCallback, безусловно, ожидает передачи обычного указателя на функцию, в то время как BIND создает что-то совершенно другое.

Тот факт, что Bind создает «вызываемую вещь», которая не «требует» этого «указателя», НЕ означает, что он создал простую функцию!

Для правильной обработки связанных функций-членов вам все еще нужно пространство как минимум из двух указателей, в то время как обычный указатель на функцию — это ОДИН указатель. Все в своем уме *) API, которые позволяют регистрировать обратные вызовы, также позволяют передавать некоторые «пользовательские данные» вместе с обратным вызовом — в таких случаях вы можете использовать их для создания небольшой оболочки, которая будет перенаправлять вызов вашей связанной функции-члена. Это уже обсуждалось во многих местах .. смотрите, например: https://stackoverflow.com/a/3453616/717732

Если вы не можете передать ЛЮБЫЕ дополнительные данные вместе с обратным вызовом, я имею в виду, что если регистрация обратного вызова позволяет вам предоставить только указатель обратного вызова, то это почти тупик. Вы не можете избежать этого, если вы не сделаете более или менее уродливые или рискованные обходные пути с ie. глобальные статические данные или генерация динамического кода.

*) это сугубо личная точка зрения. Под «вменяемым» я подразумеваю «дружественный к объекту». Низкоуровневые API очень часто не предназначены для этого, а скорее стараются максимально экономить ресурсы — и поэтому это заставляет вас делать грязную работу самостоятельно, потому что они действительно хотели сохранить эти 4/8 байтов. Иногда, иногда это действительно имеет огромное значение — они могут легче передавать обратный вызов 4 / 8b, его легко копировать, поскольку он вписывается в один регистр (в то время как указатель + userdata будет принимать 2+ регистра), операции над ним «более атомарны» и т. д. Однако чаще всего это делается для болезненно выделить что есть только ОДИН обратный звонок можно зарегистрироваться. В таких случаях это фактически делает вас очень малой разницей, будет ли это связанная функция-член какого-либо объекта или просто глобальная статическая функция: в общем, может быть только одна, так что, что угодно, просто заставьте это работать. Если это так, то просто используйте глобальную статическую переменную для указателя объекта и небольшой оболочки. Ну кроме эстетики ..

static MyObject* target;
void wrapper(..params..)
{
target->method_to_be_called(..params..);
}

// then, register it:

target = &object_to_be_called;  // \ there can be only one object
setCallback(&wrapper);          // / and only one callback registered
9

Другие решения

Других решений пока нет …