2

boost :: call_once()を使用してスレッドセーフなレイジー構築シングルトンシナリオを実現したいのですが、ベースシングルトンクラスには多くの派生クラスがあるため、getInstance()関数は引数を取り、初期化する派生クラスを決定します。コードは次のようになります、

Singleton * Singleton::getInstance(Input * a) {
if (!instance) {
    instance = buildme(a);  //buildme() will return a derived class type based on input a.
    }
return instance;
}

を使用したいのですboost::call_once()が、引数のない関数でしか使用できないようvoid (*func)()です。誰かがここで代替の解決策について知っているなら、助けてください。

ありがとう。

編集::

call_once別の質問、 ?を使用して非静的メンバー関数を呼び出す方法 このクラスの非静的init()メンバー関数がありますが、を使用して呼び出すための正しい構文が見つかりませんでしたboost::call_once()。または、作成して、そこでinit()使用されるすべてのものを静的にする必要がありますか?

ありがとう。

4

2 に答える 2

7

を使用して、追加の関数パラメーターをファンクターオブジェクトにバインドできますboost::bind。このような:

Input* input = ???;
boost::call_once(flag, boost::bind(&Singleton::getInstance, input));

boost::bind関数を呼び出すクラスのインスタンスをに渡すことにより、非静的メンバー関数を呼び出すために使用することもできますboost::bind

class Foo
{
public:
   void func(int) { /* do something */}
};

Foo f;
boost::call_once(flag, boost::bind(&foo::func, &f, 10));

C ++ 11では、を使用できますstd::bind。別の例を次に示します。boost::bind非常に似ています。

#include <utility>
#include <functional>
#include <iostream>
#include <string>

void f(int x)
{
   std::cout << "f(" << x << ")\n";
}

void g(int x, const std::string& y)
{
   std::cout << "g(" << x << ", " << y << ")\n";
}


int main()
{
   auto ten = std::bind(&f, 10);
   auto example = std::bind(&g, 20, "Twenty");

   ten();
   example();

   return 0;
}
于 2012-12-10T00:59:26.067 に答える
7

C ++ 11には、call_onceの実装が含まれています(同等のBoost.Threads機能に触発されています)。可変個引数テンプレートと完全転送を使用して、任意の数の引数を取ります。

#include <mutex>
#include <string>

void only_called_once(int i, std::string const & str) {
  // We only get here once.                                                                                                                                                         
}

void call_free() {
  static std::once_flag once;
  std::call_once(once, only_called_once, 42, "The answer");
}

呼び出し可能オブジェクトの後に任意の数の引数を渡すことができ、それらはすべて完全に転送されます(r値/ l値、const、volatileなどを含む)。

これは、メンバー関数でも機能します。呼び出し可能オブジェクトの後の最初の引数として、オブジェクトへのポインター(メンバー関数が属する型に変換可能)を渡す必要があります。

struct bar {
public:
  void only_call_once(int i, std::string const & str);
};

void call_member() {
  static std::once_flag once;
  bar instance;
  std::call_once(once, &bar::only_call_once, &instance, 42, "The answer");
}

Boostに固執している場合はboost::bind、別の回答ですでに説明したのと同じ目的で使用できます。メンバー関数はboost::bind、メンバー関数ポインターとインスタンスを次のパラメーターとして渡すことにより、上記と同じように機能します。

于 2012-12-11T16:37:50.250 に答える