Reputation: 1125
I want to use boost::call_once() to achieve a thread-safe lazy-construction singleton scenario, however, the base singleton class has many derived classes thus the getInstance() function takes an argument to determine which derived class to initialize. The code looks like,
Singleton * Singleton::getInstance(Input * a) {
if (!instance) {
instance = buildme(a); //buildme() will return a derived class type based on input a.
}
return instance;
}
I want to use boost::call_once()
, but looks like it can only be used on functions with no arguments void (*func)()
. If anybody knows about an alternative solution here please help.
Thanks.
EDIT::
Another question, how to call a non-static member function using call_once
? I have a non-static init()
member function of this class, but I couldn't find a correct syntax for calling it using boost::call_once()
. Or should I make init()
and everything used in it static?
Thanks.
Upvotes: 2
Views: 6208
Reputation: 19022
You can bind additional function parameters to a functor object using boost::bind
. Like this:
Input* input = ???;
boost::call_once(flag, boost::bind(&Singleton::getInstance, input));
You can use boost::bind
to call non-static member functions as well, by passing the instance of the class on which you want to call the function to boost::bind
.
class Foo
{
public:
void func(int) { /* do something */}
};
Foo f;
boost::call_once(flag, boost::bind(&foo::func, &f, 10));
With C++11, you can use std::bind
, here's another example. boost::bind
is quite similar.
#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;
}
Upvotes: 7
Reputation: 1149
C++11 contains an implementation of call_once (inspired by the equivalent Boost.Threads facility). It uses variadic templates and perfect forwarding to take an arbitrary number of arguments.
#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");
}
You can pass an arbitrary number of arguments after the callable and they will all be perfectly forwarded (including r-value/l-value, const, volatile, etc).
This also works for member functions. You just have to pass a pointer to an object (convertible to the type the member function belongs to) as the first argument after the callable.
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");
}
If you are stuck with Boost then you can use boost::bind
for the same purpose as has already been explained in another answer. Member functions with boost::bind
work the same way as above by passing a member function pointer and an instance as the following parameter.
Upvotes: 8