
DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=beta; d=gmail.com; h=received:message-id:date:from:reply-to:to:subject:in-reply-to:mime-version:content-type:content-transfer-encoding:references; b=pF+Zvpraxj4DWHKMjzQDRNtCoQ+iETlCcRxdPY/967Dba6UptVfsPJa3+DVBRHCDo4Yts3/JhkPhE5bOK1ckoBgblZ1gU2pNeajuhu+GYkpZA56afZxcAAxCOIvwyaAMV2hSgs2L6NiM0DaGjSk/iqVQknAxL4WF4H+RAWiKl1Q= From: Dan Rosen <dan.rosen@gmail.com>
What you've called noninstantiable should be called singleton_base so that clients derive from singleton_base.
But singleton_base has no function other than to prevent a type from being instantiated. It has no semantics relating to singleton, so it seemed reasonable to decouple them. If you want to derive a class
Agreed, but...
template called singleton_base<> from noninstantiable<>, for the (sole) purpose of making client code arguably a bit easier to follow,
Exactly. Rather than a Singleton library client needing to know that they are making a Singleton class noninstantiable, they only know they're declaring it to be used by the library. An advanced usage section can document that deriving from the base class is not needed, and that omitting that derivation permits separate instantiations of the class.
that's fine, but the noninstantiable<> / instantiable<> class template pair stand on their own in the absence of singleton. Anyway, this is getting far off-topic.
I'm not certain this is off topic. Yes, I agree that noninstantiable/instantiable could be valuable components in their own right. Whether singleton_base is implemented in terms of noninstantiable, or is merely a duplicate of the technique isn't worrisome to me.
The next point is whether requiring private ctor/dtor is better than using a noninstantiable scheme (not necessarily the one shown above).
The main point I feel is being missed is that private ctor/dtor *is* a perfectly good "noninstantiable scheme." The only difference is that it's provided by the language, and requires no code trickery on our part.
I didn't miss that. I was simply thinking of it from the perspective of the Singleton library client: with: class make_me_a_singleton : public singleton_base { ... }; without: class make_me_a_singleton { ... private: make_me_a_singleton() { }; ~make_me_a_singleton() { }; }; To me, the first ("with") version is clearer. It doesn't force defining private ctor/dtors that aren't otherwise needed and its intent is more apparent. The first version is achievable just as easily with noninstantiable as with singleton_base. If singleton_base offers nothing more than noninstantiable, then the choice of names is debatable.
The OP's goal is to prevent instantiation of a type as both a Singleton and otherwise. [snip] The question is whether the goal is acceptable. [snip] I contend that you can provide a mechanism whereby clients can ensure their type can only be instantiated by the Singleton framework, but don't require that.
I think you've just struck the heart of the issue here.
I think there are three approaches: purposely allow the flexibility you're describing, purposely disallow it, or declare it "not my problem." If you're purposely allowing classes intended for use as
Good summary.
singletons to be instantiated elsewhere anyway, you're no longer referring to the Singleton Pattern proper anymore. That's why I
It isn't clear that the library is or must slavishly follow the GoF Singleton Pattern. It can support more functionality without loss of clarity, IMO.
thought the "noninstantiable" exercise was an interesting one: it purposely disallows instantiation in any other context, thus making the client class a singleton in the strictest sense.
Fine.
But back to my point: I think the philosophical difference between our two ideas is that you are purposely allowing client classes to be instantiable outside of the singleton context by explicitly stating that "derivation from singleton_base is optional," whereas I'm saying "it's not my problem: if you want a true singleton, you'll do the right thing and prevent your class from being instantiated however you please."
To make the class instantiable by the framework, the supplied Creator policy class must have access to the ctor. You can make the ctor private and then make the Creator a friend, but then outside code can call creator<T>::create() to create an instance. If creator<T>::create() is private, and singleton<T> is a friend, then only singleton<T> can instantiate a T. That, of course, is a lot of machinery just to ensure that T can only ever be instantiated as a Singleton. It would be nice if T could be its own Creator. Then, using CRTP, T could be noninstantiable and its own Creator by deriving from, say, singleton::simple_singleton: class make_me_a_singleton : public <simple_singleton<make_me_a_singleton> { ... }; My point is that just making the ctors private doesn't close the access hole.
To summarize: I feel the singleton framework should either strictly prevent all clients from being instantiated improperly, or shouldn't care at all. The third path, which I view as "optional strictness," is oxymoronic, and a waste of time for the singleton framework to attempt to provide.
It isn't a waste if it simplifies syntax. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;