7

boost::bind戻りオブジェクトに埋め込まれた関数ポインタがNULL/ nullptr/0の場合、それを呼び出す以外のアクションを実行する必要があります。オブジェクトにヌル関数ポインタが含まれているかどうかを判断するにはどうすればよいですか?

補遺

  1. 戻りオブジェクトがテンプレート関数のさまざまな呼び出しシグネチャで使用されるboost::functionため、 s を使用して比較できるとは思いません。boost::bind
  2. 簡単な例:
template <typename BRO>
Retval do_stuff(BRO func, enum Fallback fallback)
{
    if (func == NULL)
    {
        return do_fallback(fallback);
    }
    else
    {
        return use_retval(func());
    }
}

do_stuff(boost::bind(FuncPtrThatMightBeNull, var1, var2), fallback);

解決

呼び出し先の関数のアリティは変わらないので、バインドの戻りオブジェクトを に「キャスト」してboost::function呼び出すことができます.empty()

Retval do_stuff(boost::function<Retval()> func, enum Fallback fallback)
{
    if (func.empty())
        return do_fallback(fallback);
    else
        return use_retval(func());
}
4

4 に答える 4

6

ダミー関数にバインドできます。

void dummy() { /* has differing behaviour */ }
// ...
boost::bind(&dummy)();

... または、Boost.Bindと一緒に使用していると仮定するとBoost.Function、デフォルトで構築された関数オブジェクトを返し、empty()それを呼び出す前に確認します。

typedef boost::function<void (void)> F;
F create() { return F(); }

void use() {
    F f = create();
    if(f.empty()) {
        /* ... */
    }
}

更新について:
次のような別の関数にバインドする際の問題が何であるかはまだわかりません。

template <typename BRO>
Retval do_stuff(BRO func)
{
    return func();
}

if(funcPtr) {
    do_stuff(boost::bind(&use_retval, boost::bind(funcPtr, a, b)));
} else {
    do_stuff(boost::bind(&do_fallback, fallback));
}

その処理を呼び出し元のコードから移動したい場合は、変数アリティをサポートするために可変個引数テンプレート関数をエミュレートできます。

template<class R, class T1> 
boost::function<R (T1)> 
bind_wrap(R (*fnPtr)(), T1& t1, Fallback fallback) {
    if(fnPtr) return boost::bind(&use_retval,  boost::bind(funcPtr, t1));
    else      return boost::bind(&do_fallback, fallback);
}

template<class R, class T1, class T2> 
boost::function<R (T1, T2)> 
bind_wrap(R (*fnPtr)(T1, T2), T1& t1, T2& t2, Fallback fallback) {
    if(fnPtr) return boost::bind(&use_retval,  boost::bind(funcPtr, t1, t2));
    else      return boost::bind(&do_fallback, fallback);
}

// ... etc. for all needed arities

do_stuff(bind_wrap(funcPtr, var1, var2, fallback));

...または、上記のアプローチを使用して、boost::function<>オブジェクトまたは独自のラッパーを生成functor.empty()し、do_stuff().

于 2010-01-06T02:10:57.767 に答える
1

これを行うためにラッパーオブジェクトを作成します。次のようなもの

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

int aFunction(int i, int j)
{
  std::cout<<"In a Function"<<std::endl;
  return i+j;
}

struct DefaultingFromFnPtr : public boost::function< int(int,int) >
{
  explicit DefaultingFromFnPtr( int(*fn)(int,int) ) : fn_(fn) {}
  int operator()(int i, int j) const
  {
    if (fn_!=NULL) return fn_(i, j);
    return 7;
  }
  int(*fn_)(int,int);
};

template<typename T>
void do_stuff( T t )
{
  std::cout<<"RETURNED "<<t()<<std::endl;
}

int main( int argv, const char** argc)
{

  int(*mightBeNullFnPtr)(int,int) = NULL;
  if( argv>1)
  {
    mightBeNullFnPtr = & aFunction;
  }

  int var1 = 10;
  int var2 = 20;

  do_stuff( boost::bind( DefaultingFromFnPtr( mightBeNullFnPtr ), var1, var2 ) );
}

これをコンパイルして引数なしで実行すると、mightBeNullFnPtrがNULLに設定され、ラッパークラスでdo_stuffが呼び出されるため、7が出力されます。引数付きで実行すると、mightByNullFnPtrがaFunctionに設定され、それを使用してdo_stuffが呼び出され、30が出力されます。

より汎用性が必要な場合は、DefaultingFromFnPtrラッパークラスをテンプレート化する必要がありますが、これは非常に簡単です。

于 2010-01-11T03:33:23.797 に答える
0

クラッシュが呼び出し時にのみ発生したとしても、null ポインター (= バインド オブジェクトの作成) を使用して boost::bind を呼び出すことは、未定義の動作と見なす必要があると確信しています。

于 2010-01-06T02:08:25.290 に答える
-1

ブーストをハックする必要があります。

boost::bind はunspecified-nn を返します。これらのクラスで有効なのは operator() だけです。あなたが知っている唯一の他のことは、それらがコピー構築可能であり、result_type の typedef を持っていることです (ちなみに、結果の型のテンプレートは必要ありません)。

あなたは何か他のものが欲しい - そのため、ブーストで unspecified -nnの定義を見つける必要があります(いくつかあるかもしれません)。それらをハックして、必要な条件をチェックする is_null() メンバー関数を持ち、それをテストとして呼び出します。 .

もちろん、これは、テンプレート関数で常に boost::bind されたオブジェクトを取得することが確実であると仮定した場合です。誰かが通常の関数ポインタを渡そうとすると、コンパイルされません。これを回避するには、いくつかのテンプレート マジックが必要です。

于 2010-01-11T02:28:29.120 に答える