Reputation: 2359
When using the Meyers singleton:
class Singleton
{
public:
static Singleton& instance()
{
static Singleton instance;
return instance;
}
void Hello()
{
std::cout <<"Hello!\n";
}
protected:
Singleton() = default;
~Singleton() {};
private:
Singleton(Singleton const&);
Singleton& operator=( Singleton const& );
};
You are able to call the instance as follow:
Singleton::instance().Hello();
or
Singleton& s = Singleton::instance();
s.Hello();
But I'm wondering if there is a way to block this:
Singleton::instance().instance();
How to avoid to call instance() as a method (with the .
) and only support the static call with the ::
?
Is there a way to use static_assert, template enable_if or anything else?
Upvotes: 1
Views: 218
Reputation: 303537
First, I don't think this is a practical concern. Nobody is going to write Singleton::instance().instance().instance().Hello()
. Or rather, if people are writing that on purpose, I think you have bigger problems. This is fine, as-is.
If you really want to prevent that, then you just have to move instance()
outside of the class so it ceases to be a member function. There's nothing for you to assert or constrain, since you cannot tell if your static member function was called on an object or not (and you cannot overload a static member function with a non-static one taking the same argument list). Either you can write both Singleton::instance()
and Singleton::instance().instance()
, or neither.
Simplest is just:
class Singleton {
// ...
friend Singleton& make_singleton();
};
Singleton& make_singleton() {
static Singleton instance;
return instance;
}
Now it's just make_singleton().Hello()
, and there's no other way to write that at all. This can be arbitrarily generalized by wrapping it in a singleton class template factory:
template <typename T>
struct SingletonFactory
static T& instance() {
static T instance;
return instance;
}
};
SingletonFactory<Singleton>::instance().Hello(); // ok
SingletonFactory<Singleton>::instance().instance().Hello(); // error
Upvotes: 7