81

次のコードにより、cl.exeがクラッシュします(MSVS2005)。
ブーストバインドを使用して、myclassのメソッドを呼び出す関数を作成しようとしています。

#include "stdafx.h"
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <functional>

class myclass {
public:
    void fun1()       { printf("fun1()\n");      }
    void fun2(int i)  { printf("fun2(%d)\n", i); }

    void testit() {
        boost::function<void ()>    f1( boost::bind( &myclass::fun1, this ) );
        boost::function<void (int)> f2( boost::bind( &myclass::fun2, this ) ); //fails

        f1();
        f2(111);
    }
};

int main(int argc, char* argv[]) {
    myclass mc;
    mc.testit();
    return 0;
}

私は何が間違っているのですか?

4

3 に答える 3

110

代わりに以下を使用してください。

boost::function<void (int)> f2( boost::bind( &myclass::fun2, this, _1 ) );

これにより、関数オブジェクトに渡された最初のパラメーターがプレースホルダーを使用して関数に転送されます。パラメーターの処理方法をBoost.Bindに指示する必要があります。あなたの式では、引数を取らないメンバー関数としてそれを解釈しようとします。一般的な使用パターンについては、
たとえばここまたはここを参照してください。

VC8s cl.exeはBoost.Bindの誤用で定期的にクラッシュすることに注意してください。疑わしい場合は、gccでテストケースを使用すると、出力を読み通すと、テンプレートパラメーターBind -internalsがインスタンス化されたような良いヒントが得られるでしょう。

于 2010-02-20T23:40:33.337 に答える
1

Boost.Bindは、元々 std :: bind1st()およびstd :: bind2nd()を必要としていた機能を単純化および一般化するライブラリです。

例1.1:互換性のある関数を使用したstd :: for_each()

#include <vector>
#include <algorithm>
#include <iostream>

void print(int i)
{
  std::cout << i << '\n';
}

int main()
{
  std::vector<int> v{1, 3, 2};
  std::for_each(v.begin(), v.end(), print);
}

std :: for_each()の3番目のパラメーターは、唯一のパラメーターを期待する関数または関数オブジェクトです。例1.1では、std :: for_each()は、コンテナーv内の数値を唯一のパラメーターとしてprint()に次々に渡します。

シグニチャがアルゴリズムの要件を満たさない関数を渡す必要がある場合、それはより困難になります。たとえば、print()で出力ストリームを追加のパラメーターとして受け入れる場合、 std :: for_each()でそのまま使用することはできなくなります。

例1.2。std :: for_each()std :: bind1st()

#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>

class print : public std::binary_function<std::ostream*, int, void>
{
public:
  void operator()(std::ostream *os, int i) const
  {
    *os << i << '\n';
  }
};

int main()
{
  std::vector<int> v{1, 3, 2};
  std::for_each(v.begin(), v.end(), std::bind1st(print{}, &std::cout));
}

例1.1と同様に、例1.2はvのすべての数値を標準出力に書き込みます。ただし、今回は、出力ストリームがパラメーターとしてprint()に渡されます。これを行うために、関数print()は、 std::binary_functionから派生した関数オブジェクトとして定義されます。

Boost.Bindを使用すると、 print()を関数から関数オブジェクトに変換する必要はありません。代わりに、 boost/bind.hppで定義されている関数テンプレートboost::bind()を使用します。

例1.3:std :: for_each()boost :: bind()

#include <boost/bind.hpp>
#include <vector>
#include <algorithm>
#include <iostream>

void print(std::ostream *os, int i)
{
  *os << i << '\n';
}

int main()
{
  std::vector<int> v{1, 3, 2};
  std::for_each(v.begin(), v.end(), boost::bind(print, &std::cout, _1));
}

例1.3では、print()を関数オブジェクトとしてではなく、関数として使用しています。print()は2つのパラメーターを想定しているため、関数をstd :: for_each()に直接渡すことはできません。代わりに、boost :: bind()std :: for_each()に渡され、print()がboost :: bind()の最初のパラメーターとして渡されます。

print()は2つのパラメーターを想定しているため、 boost :: bind()にもこれらの2つのパラメーターを渡す必要があります。これらは、std::coutおよび_1へのポインタです。

_1はプレースホルダーです。Boost.Bin dは、_1から_9までのプレースホルダーを定義します。これらのプレースホルダーは、boost :: bind()に、最大数のプレースホルダーと同じ数のパラメーターを期待する関数オブジェクトを返すように指示します。例1.3のように、プレースホルダー_1のみが使用されている場合、boost :: bind()は単項関数オブジェクト(唯一のパラメーターを期待する関数オブジェクト)を返します。std :: for_each()は1つのパラメーターのみを渡すため、この場合はこれが必要です。

std :: for_each()は単項関数オブジェクトを呼び出します。関数オブジェクトに渡される値(コンテナーvからの数値)は、プレースホルダー_1の位置を取ります。boost :: bind()は、数値とstd :: coutへのポインターを受け取り、それらをprint()に転送します。

std :: bind1st()std :: bind2nd()のように、boost :: bind()はパラメータを値で受け取ることに注意してください。呼び出し側プログラムがstd::coutをコピーしようとするのを防ぐために、print()はストリームへのポインターを期待します。Boost.Refは、参照によってパラメーターを渡すことができる関数を提供します。

例1.4は、 boost :: bind()を使用してバイナリ関数オブジェクトを定義する方法を示しています。アルゴリズムstd::sort()を使用します。これは、3番目のパラメーターとして2進関数を期待します。

例1.4std :: sort()boost :: bind()

#include <boost/bind.hpp>
#include <vector>
#include <algorithm>
#include <iostream>

bool compare(int i, int j)
{
  return i > j;
}

int main()
{
  std::vector<int> v{1, 3, 2};
  std::sort(v.begin(), v.end(), boost::bind(compare, _1, _2));
  for (int i : v)
    std::cout << i << '\n';
}

例1.4では、プレースホルダー_2が使用されているため、バイナリ関数オブジェクトが作成されます。アルゴリズムstd::sort()は、コンテナーvからの2つの値を使用してこのバイナリ関数オブジェクトを呼び出し、戻り値を評価してコンテナーをソートします。関数compare()は、vを降順でソートするように定義されています。

compare()はバイナリ関数であるため、std :: sort()に直接渡すことができますただし、 boost :: bind()を使用すると、パラメーターの順序を変更できるため、それでも意味があります。たとえば、コンテナを昇順で並べ替えたいが、compare()を変更したくない場合は、 boost :: bind()を使用できます。

例1.5std :: sort()boost :: bind()およびプレースホルダーの順序の変更

#include <boost/bind.hpp>
#include <vector>
#include <algorithm>
#include <iostream>

bool compare(int i, int j)
{
  return i > j;
}

int main()
{
  std::vector<int> v{1, 3, 2};
  std::sort(v.begin(), v.end(), boost::bind(compare, _2, _1));
  for (int i : v)
    std::cout << i << '\n';
}
于 2021-06-30T03:46:00.507 に答える
0

以下は私のために働きます。

class test_component
{
private:
    void on_wait_complete(const int i);
};

void test_component::on_wait_complete (const int i)
{
    cout << "on_wait_complete was called" << endl;

    return;
}

int main()
{
    // timerPtr_ is a variable declared in class test_component.
    timerPtr_->async_wait(boost::bind(&test_component::on_wait_complete, this, _1));
}
于 2022-01-29T11:28:09.813 に答える