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

Der*_*rek 2 c++ multithreading boost

我想使用boost :: call_once()来实现线程安全的lazy-construction单例场景,但是,基本单例类有许多派生类,因此getInstance()函数接受一个参数来确定要初始化的派生类.代码看起来像,

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

我想使用boost::call_once(),但看起来它只能用于没有参数的函数void (*func)().如果有人知道替代解决方案,请帮忙.

谢谢.

编辑::

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

谢谢.

Cha*_*had 7

您可以使用将其他函数参数绑定到仿函数对象boost::bind.像这样:

Input* input = ???;
boost::call_once(flag, boost::bind(&Singleton::getInstance, input));
Run Code Online (Sandbox Code Playgroud)

您也可以boost::bind通过传递要调用该函数的类的实例来调用非静态成员函数boost::bind.

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

Foo f;
boost::call_once(flag, boost::bind(&foo::func, &f, 10));
Run Code Online (Sandbox Code Playgroud)

使用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;
}
Run Code Online (Sandbox Code Playgroud)

  • 实际上,C++ 11中的std :: call_once接受任意数量的参数(在一次标志和可调用之后),这些参数完全转发到callable,因此在这种情况下不需要std :: bind. (3认同)

Joh*_*342 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");
}
Run Code Online (Sandbox Code Playgroud)

你可以在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");
}
Run Code Online (Sandbox Code Playgroud)

如果你被Boost困住,那么你可以使用boost::bind与另一个答案中已经解释过的相同的目的.成员函数与boost::bind工作如上通过使一个成员函数指针和一个实例如下面的参数相同的方式.