如何强制转换为boost :: bind(&myClass :: fun,this,_1,_2,_3)到typedef void(*fun)(arg1,arg2,arg3)?

Duc*_*een 9 c++ boost boost-bind c++03

在lib Bullet中定义了一种类型:

typedef void (*btNearCallback)(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, const btDispatcherInfo& dispatchInfo);
Run Code Online (Sandbox Code Playgroud)

在那里的文档中提供了一个使用示例(第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);
}
Run Code Online (Sandbox Code Playgroud)

我将这个示例代码复制到我的类defention中,所以我的类得到了这个函数,我将能够做这样的演员:

    dispatcher->setNearCallback(boost::bind(&BulletAPIWrapper::MyNearCallback, this, _1, _2, _3));
Run Code Online (Sandbox Code Playgroud)

而不是像dispatcher->setNearCallback(MyNearCallback);Bullet教程那样的C.

然而我的VS2010 sp1给了我一个错误:

Error   44  error C2664: 'btCollisionDispatcher::setNearCallback' : cannot convert parameter 1 from 'boost::_bi::bind_t<R,F,L>' to 'btNearCallback'
Run Code Online (Sandbox Code Playgroud)

所以我想知道如何将boost :: bind转换为这样的typedef?

是否有可能具有静态类函数(或至少是全局函数):

void MyNearCallback(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, const btDispatcherInfo& dispatchInfo, BulletAPI* api) {
}
Run Code Online (Sandbox Code Playgroud)

呼叫 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'
Run Code Online (Sandbox Code Playgroud)

我也试过这里描述的:

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) ) );
Run Code Online (Sandbox Code Playgroud)

但我从中得到了这样的错误:

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

que*_*atl 9

为什么你认为你"应该能够像...一样"?setNearCallback当然希望传递一个普通的函数指针,而BIND会产生完全不同的东西.

Bind生成一个"可调用的东西"并不"需要'这个'指针"的事实并不意味着它产生了一个简单的函数!

要正确处理绑定的成员函数,您仍然需要至少两个指针的空间,而普通函数指针是一个指针.允许您注册回调的所有sane*)API还允许您传递一些'userdata'以及回调 - 在这种情况下,您可以使用它来创建小包装器,将调用重定向到绑定的成员函数.这已在很多地方讨论过了..请参阅例如:https://stackoverflow.com/a/3453616/717732

如果你不能传递任何额外的数据和回调,我的意思是,如果回调注册允许你只提供回调指针,那么它几乎是死路一条.除非你做一些或多或少的丑陋或冒险的解决方法,否则你无法摆脱这种情况.全局静态数据或动态代码生成..

*)这纯粹是个人观点."理智"我的意思是"对象友好".低级API通常并不是严格意义上的,而是尽可能地节省资源 - 因此它会迫使您自己完成脏工作,因为他们想要真正保存那些4/8字节.有时,有时,这实际上会产生巨大的影响 - 它们可以更容易地传递4/8b回调,它很容易复制,因为它适合单个寄存器(而指针+用户数据将需要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
Run Code Online (Sandbox Code Playgroud)