9

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

dispatcher->setNearCallback(MyNearCallback);BulletチュートリアルのようなCの代わりに。

それでも私のVS2010sp1は私にエラーを与えます:

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'
4

1 に答える 1

9

なぜ「..のようにキャストできるはずだ」と思いますか? setNearCallback は確かに通常の関数ポインタが渡されることを期待していますが、BIND はまったく異なるものを生成します..

Bind が「'this' ポインターを必要としない」「呼び出し可能なもの」を生成するという事実は、それが単純な関数を生成したことを意味しません!

通常の関数ポインターは 1 つのポインターですが、バインドされたメンバー関数を適切に処理するには、少なくとも 2 つのポインターのスペースが必要です。コールバックを登録できるすべての正常な*) API では、コールバックとともに「ユーザーデータ」を渡すこともできます。そのような場合、それを使用して、バインドされたメンバー関数への呼び出しをリダイレクトする小さなラッパーを作成できます。これはすでに多くの場所で議論されています..例を参照してください: https://stackoverflow.com/a/3453616/717732

コールバックと一緒に追加のデータを渡すことができない場合、つまり、コールバック登録でコールバック ポインターのみを提供できる場合、それはほとんど行き止まりです。多かれ少なかれ醜い、または危険な回避策を ie. グローバル静的データまたは動的コード生成..

*) これは完全に個人的な見解です。「正気」とは、「オブジェクトフレンドリー」を意味します。多くの場合、低レベル API は厳密には意図されたものではなく、可能な限りリソースを節約しようとします。そのため、4/8 バイトを本当に節約したかったため、自分で汚い作業を行う必要があります。時々、これは実際に大きな影響を与えます - 4/8b コールバックをより簡単に渡すことができ、単一のレジスタに収まるので簡単にコピーできます (一方、ポインタ + ユーザーデータは 2 つ以上のレジスタを必要とします)。 」などですが、ほとんどの場合、これは、登録できるコールバックが 1 つしかないことを痛烈に強調するために行われます。. そのような場合、それが何らかのオブジェクトのバインドされたメンバー関数であろうと、単なるグローバルな静的関数であろうと、実際にはほとんど違いはありません。全体として、存在できるのは 1 つだけです。この場合は、オブジェクト ポインターと小さなラッパーにグローバルな静的変数を使用します。まあ、美学を除いて..:

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
于 2013-02-10T23:46:26.093 に答える