22

単純な関数ポインターを期待するメソッドに boost::bind を渡したい (同じ署名)。

typedef void TriggerProc_type(Variable*,void*);
void InitVariable(TriggerProc_type *proc);
boost::function<void (Variable*, void*)> triggerProc ...
InitVariable(triggerProc);

error C2664: 'InitVariable' : cannot convert parameter 1 from 
'boost::function<Signature>' to 'void (__cdecl *)(type *,void *)'

boost::function の格納を回避して、バインドされたファンクターを直接渡すことができますが、同様のエラーが発生します。

error C2664: 'blah(void (__cdecl *)(type *,void *))' : cannot convert parameter
1 from 'boost::_bi::bind_t<R,F,L>' to 'void (__cdecl *)(type *,void *)'
4

5 に答える 5

42

受け入れられた答えが些細なケースでしか機能しないことに気づいた人はいますか? function<>::target() が C コールバックにバインドできるオブジェクトを返す唯一の方法は、C コールバックにバインドできるオブジェクトで構築された場合です。その場合は、直接バインドして、最初から意味のないすべての function<> をスキップできます。

考えてみれば、これに対する魔法の解決策はありません。C スタイルのコールバックは、実行可能コードを指す単一のポインターとして格納されます。重要な boost::function<> には、少なくとも 2 つのポインターが必要になります。1 つは実行可能コードへのポインターで、もう 1 つは呼び出しをセットアップするために必要なデータへのポインターです (たとえば、バインドされたメンバーの場合は「this」ポインター)。関数)。

C コールバックで boost::function と boost::bind を使用する正しい方法は、コールバック シグネチャを満たすシム関数を作成し、呼び出す function<> を特定して呼び出すことです。通常、C のコールバックには、「ユーザー データ」に対して何らかの種類の void* があります。それはあなたの関数ポインタを隠しておく場所です:

typedef void (*CallbackType)(int x, void* user_data);
void RegisterCallback(CallbackType cb, void* user_data);

void MyCallback(int x, void* userData) {
  boost::function<void(int)> pfn = static_cast<boost::function<void(int)> >(userData);
  pfn(x);
}

boost::function<void(int)> fn = boost::bind(myFunction(5));
RegisterCallback(MyCallback, &fn);

もちろん、コールバック署名に何らかのユーザー データ ポインターが含まれていない場合は、うまくいきません。ただし、ユーザー データ ポインターを含まないコールバックは、ほとんどの現実のシナリオでは既に使用できず、書き直す必要があります。

于 2010-08-10T21:32:04.930 に答える
12

boost::function の target() メンバー関数を使いたいと思います(それは一口ではありませんか...)

#include <boost/function.hpp>
#include <iostream>

int f(int x)
{
  return x + x;
}

typedef int (*pointer_to_func)(int);

int
main()
{
  boost::function<int(int x)> g(f);

  if(*g.target<pointer_to_func>() == f) {
    std::cout << "g contains f" << std::endl;
  } else {
    std::cout << "g does not contain f" << std::endl;
  }

  return 0;
}
于 2008-11-11T23:01:08.063 に答える
4

バインドで動作させることができますか?

cb_t cb = *g.target<cb_t>(); //target returns null

これは仕様によるものです。基本的にbindは全く違う型を返すので、これがうまくいくわけがありません。基本的に、バインダー プロキシ オブジェクトを C 関数ポインターに変換することはできません (関数オブジェクトではないため)。によって返される型boost::bindは複雑です。現在の C++ 標準では、必要なことを行う良い方法はありません。C++0x には、次のdecltypeようなことを実現するためにここで使用できる式が組み込まれます。

typedef decltype(bind(f, 3)) bind_t;
bind_t target = *g.target<bind_t>();

これが機能する場合と機能しない場合があることに注意してください。私はそれをテストする方法がありません。

于 2009-02-04T16:56:20.917 に答える
2

ブースト メーリング ページを参照してください [ブースト] [機能] ブースト::mem_fn およびブースト::バインドで target() を使用する際の問題

于 2009-02-27T03:21:11.433 に答える
0

バインドで動作させることができますか?

#include <boost/function.hpp>
#include <boost/bind.hpp>

void f(int x)
{
    (void) x;
    _asm int 3;
}

typedef void (*cb_t)(int);

int main()
{
    boost::function<void (int x)> g = boost::bind(f, 3);
    cb_t cb = *g.target<cb_t>(); //target returns null
    cb(1);

    return 0;
}

更新:さて、その意図は、メソッドを関数コールバックにバインドすることです。んで、どうする?

于 2009-02-04T16:45:41.453 に答える