0

There are many folks out there that claim their singleton implementation to be robust and general because it uses metaprogramming constructs.

My goal is to enforce a singleton policy onto a derived class so that I do not have to explicitly (manually) declare the derived class' constructors as private. I think there's a way to naively add the instance static variable and the getter as a policy by making the templated singleton a friend of the class you derive. But that's not at all elegant.

I started with this code, that, among other things, is given as being a correct (i.e. complete) design of a singleton, while it is clearly allowing for multiple instances:

template <class CWrappedClass>
class CSingleton
{
protected:
    static CWrappedClass* ms_instance;
private:
    CSingleton(){}
    CSingleton(const CSingleton& ) {}
    CSingleton& operator = (const CSingleton&) {}

public:
    static CWrappedClass& GetInstance()
    {
        if (ms_instance == NULL)
            ms_instance = new CWrappedClass;
        return *ms_instance;
    }
};

template <class CWrappedClass>
CWrappedClass* CSingleton<CWrappedClass>::ms_instance = NULL;

And a singleton client of this "policy", using CRTP:

class CThing : public CSingleton<CThing>
{
     // friend class CSingleton<CThing>; // only if ctor is private!
public:
    void DoNothing()
    {
        std::cout<<" Nothing \n";
    }
    CThing()
    {
        std::cout<<" single ";
    }
};

NOTE this is not a correct implementation of a CRTP Singleton policy, it's merely part of the question!

The code won't compile as is. The base singleton policy class has its constructor declared private, so it can't support derived instances unless the child is a friend of this class. People usually make the constructors protected, which means there's nothing to keep a user from making derived class non-singletonian.

Problem/Question: Is there any mechanism to enforce a singleton policy without having to make the derived class' constructors private manually?

teodron
  • 1,350
  • 1
  • 17
  • 38
  • 1
    IMHO you never need a singleton. Just instantiate it once and that's it. [What is so bad about singletons?](http://stackoverflow.com/questions/137975/what-is-so-bad-about-singletons) – RedX Nov 12 '12 at 16:14
  • This is a classic topic, let's tolerate the singleton pattern for now, just for educational purposes, by solving this conditioned puzzle. There are tons of reasons for not using it, but I would like not to have them written down in any answers to this thread :).. – teodron Nov 12 '12 at 16:16
  • I don't see a question here. What, exactly, is the question? – John Dibling Nov 12 '12 at 16:16
  • `friend class CWrappedClass;` work, by any chance? – Yakk - Adam Nevraumont Nov 12 '12 at 16:19
  • Singleton should have a protected constructor. CThing should have a private constructor and make its base class a friend. – CashCow Nov 12 '12 at 16:21

1 Answers1

2

In case you do wish to use this pattern:

  1. Constructor of the template should be protected, not private, so that the derived class has access to it. Otherwise its own constructor cannot construct the base class.

  2. Derived class can make the template (which is its base class) a friend and have a private constructor.

Alternatively, have a macro that you implement that actually constructs the instance from the derived class in its compilation unit. When I did use a similar model (by force, fixing code that used singletons and I coudn't change that, only the way the actual singleton was implemented), I went for this option, which actually went through a boost::once construct in its .cpp file.

CashCow
  • 29,087
  • 4
  • 53
  • 86
  • At the moment, this strategy is the only one. I could close the question as it seems there is no other way other than making the derived classes have their constructor(s) private. – teodron Nov 12 '12 at 16:53
  • The derived classes should have private constructors so you can't just create one from anywhere, thus enforcing their singleton status. – CashCow Nov 13 '12 at 09:37
  • Ok, going for the macro helper as it's a bit easier than writing by hand the constructors and the '=' operator in the private section. Question closed, thanks. – teodron Nov 13 '12 at 10:26