There's no way for a constructor to know at compile time where or how many times it will be called; constructors are just functions, and functions don't know anything about their contexts. Consider that any static_assert
s will be evaluated when the class is compiled, but this can (and almost certainly will!) happen in an entirely different translation unit from code that actually instantiates the class.
In any case, it seems unlikely that this would be helpful, because you must have some way to access singletons throughout your codebase.
Additionally, it's unclear why you want to permit your singletons to have public constructors. If you want to enforce singleton behavior at compile time for a completely arbitrary class just by adding an inheritance declaration, you're out of luck; arbitrary classes can be, well, arbitrarily constructed.
Since you're transitioning from the ACE singleton, I suggest you use a similar API; note that the ACE singleton documentation recommends making your singleton constructors private.
If, however, you just want some way to force your client to write a constructor that can't (easily) be called improperly, you can do something like this:
template <typename T>
class SingletonBase {
protected: class P { friend class SingletonBase<T>; P() = default; };
public:
SingletonBase(P) {}
static T& Instance() {
static T instance { P {} };
return instance;
}
};
(You will also need to delete
the base class's copy and move constructors. Here is a working example use case. Note that declaring P's constructor =default
does not prevent the singleton class from default-initializing instances of P. )
Now, because the base class constructor takes an argument of type P, the singleton class implementation must pass a P to its parent class constructor. But since the constructor for P is private, the singleton class won't be able to construct an instance of P except by copy or move construction, so its constructor must take an instance of P. But since P itself is protected, only the singleton class and the parent class can actually use it, so effectively the only possible call to the child's constructor must be in the Instance
method.
Note that you do not need to explicitly declare and define the singleton-class's constructor, which would be ugly because of the need to use SingletonBase<Singleton>::P
. You can simply expose the constructor with a using
declaration:
using BASE = SingletonBase<Myclass>;
using BASE::SingletonBase;