如何在带参数的函数上使用boost :: call_once()

时间:2012-12-10 00:52:28

标签: c++ multithreading boost

我想使用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)()的函数。如果有人知道替代解决方案,请帮助。

感谢。

EDIT ::

另一个问题,如何使用call_once调用非静态成员函数?我有这个类的非静态init()成员函数,但我找不到使用boost::call_once()调用它的正确语法。或者我应该使init()和其中使用的所有东西都是静态的吗?

感谢。

2 个答案:

答案 0 :(得分: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;
}

答案 1 :(得分: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");
}

你可以在callable之后传递任意数量的参数,它们都将被完美转发(包括r-value / l-value,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的成员函数的工作方式与上面相同,方法是将成员函数指针和实例作为以下参数传递。