4
typedef boost::function<void (int,bool)> MyCallback;
void RegisterCallback(MyCallback callback);

class A {
public:
    void GoodCallback(int intArg,bool boolArg) {
        printf("calling GoodCallback (%d,%s)\n",intArg,boolArg?"true":"false");
    }

    void BadCallback(int intArg) {
        printf("calling BadCallback (%d)\n",intArg);
    }
};

int TestFunction() {
    A * myA=new A();
    RegisterCallback(boost::bind(&A::GoodCallback,myA,_1,_2));

    RegisterCallback(boost::bind(&A::BadCallback,myA,_1));

    return 0;
}

RegisterCallback への 2 回目の呼び出しをコンパイルしないようにする方法はありますか?

コンテキストについて:
最近、コールバック シグネチャを変更し、bool 引数を追加しました。これを使用しているものはすべて更新したと思っていましたが、間違っていました。RegisterCallback署名を変更するたびに名前を変更する以外に、すべての引数が使用されるようにコンパイラーに強制させる方法が必要です。

4

4 に答える 4

2

ドキュメントによると

余分な引数は黙って無視されます

_Nプレースホルダーをサポートするには、このようにする必要があります。目撃者:

void foo (int a, const char* b) {
  std::cout << "called foo(" << a << "," << b << ")" << std::endl;
}

int main () {
  boost::bind(foo,_1, _2)(1, "abc", foo, main, 2.0);
  boost::bind(foo,_2, _5)(3.0, 2, foo, main, "def");
}

版画

called foo(1,abc)
called foo(2,def)

引数リストの最初、最後、または途中にある引数の組み合わせは無視できます。

_Nプレースホルダーのようなものをサポートしない、より単純なバインダーが必要です。ブーストにはないようです。

于 2011-07-26T22:11:13.010 に答える
1

問題はありませんboost::function; 問題は、関数オブジェクトが返すものがパラメータとして何でもboost::bind取るということです。バインドは、多かれ少なかれランタイム定義であり、コンパイル時定義ではありません。したがって、オブジェクトは任意ので使用できます。boost::bindboost::function

[編集]わかりました、どうやら問題boost::functionあります。しかし、それだけが問題ではありません。

于 2011-07-26T20:53:07.027 に答える
1

代わりにいつでも使用できますstd::function<...>

以下は VS2010 SP1 でコンパイルされません。

#include <functional>

void foo();
void bar(int);

int main()
{
    std::function<void ()> f= std::bind(foo);
    std::function<void ()> g= std::bind(bar); // does not match signature, does not compile.
    return 0;
}
于 2011-07-27T01:10:01.870 に答える
0

私はこの答えに少し遅れていますが、問題はバインディングであるため、コールバック登録関数のテンプレート化されたバージョンと通常の関数ポインターの別のバージョンを使用して、後でこの手順を実行できます。

template<typename C>
void RegisterCallback(void (C::* func)(int, bool), C* inst)
{
  MyCallback callback(boost::bind(func, inst, _1,_2));
}

void RegisterCallback(void (*func)(int, bool))
{
  MyCallback callback(func);
}

A * myA = new A();     
RegisterCallback(&A::GoodCallback, myA);      
RegisterCallback(&A::BadCallback, myA); // DOES NOT COMPILE

RegisterCallback(GoodCallback);
RegisterCallback(BadCallback); // DOES NOT COMPILE

これは VS2010 で期待どおりに機能しますが、メンバー関数と非メンバー関数を正しく処理するために 1 つではなく 2 つのコールバック登録関数が必要になるという欠点があります。

別のオプションとして、boost function_types ライブラリを参照することもできます。関数ポインターのパラメーターの型を抽出し、それらを MPL シーケンスとして返す parameter_types メタ関数を提供します。次に、ちょっとしたテンプレート マジックを使用して、次のようなコールバック関数のパラメーターを検証できます。

#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/function_types/parameter_types.hpp>
#include <boost/mpl/equal.hpp>

using namespace boost;
using namespace boost::function_types;

template< typename Function >
void RegisterCallback(Function f)
{
   BOOST_MPL_ASSERT(( 
      mpl::equal< 
        parameter_types< Function >, 
        parameter_types< void(int,bool) >
      > 
   ));

   MyCallback callback(f);
}

template<typename Function, typename T>
void RegisterCallback(Function f, T* inst)
{
   BOOST_MPL_ASSERT(( 
     mpl::equal< 
       parameter_types< Function >, 
       parameter_types< void (T::*)(int,bool) >
     > 
   ));

   MyCallback callback(boost::bind(f, inst, _1, _2));  
}

これは VS2010 でも期待どおりに機能しますが、2 つの関数宣言が必要ですが、それらを構造体内で定義する (そして T の既定のテンプレート パラメーター引数を使用する) 場合は 1 つにまとめることができるはずです。

于 2011-07-28T11:10:14.643 に答える