Petwoip
Petwoip

Reputation: 1345

Template class: No appropriate default constructor avaialable. But some of my classes cannot have default constructors

I'm experiencing a weird issue in which I need to have a default constructor for my template class to work, but some of the classes I'd like to use with the template cannot have default constructors.

What I mean by some classes cannot have default constructors is they have a const reference field, hence, they must be set in the constructor/initialization list. If I have a default constructor, there is nothing to set these references to.

So, I guess there are two possible solutions to this: Find a way to allow for non-default constructors in the template class sometimes or find a way to set the const reference fields in a default constructor.

How do I resolve this?

Here's my template code:

#pragma once

template<class T>
class Singleton
{
public:
    static T* getInstance()
    {
        if(!instance) instance = new T;
        return instance;
    }
static void setInstance(T* inst)
{
    instance = inst;
}
protected:
    Singleton();
    ~Singleton();
private:
    Singleton(Singleton const&);
    Singleton& operator=(Singleton const&);
    static T* instance;
};

template<class T> T* Singleton<T>::instance = 0;

Here's where I set the const reference (in a .cpp):

InputHandler::InputHandler(const sf::Input& inputObject)
    : input(inputObject)
{

And input is defined in the header:

const sf::Input& input;

I have to use a constant reference because of this area of code (in a different file):

const sf::Input& input = window.GetInput();
InputHandler* inputHandler = new InputHandler(input);
Singleton<InputHandler>::setInstance(inputHandler);

GetInput() is not one of my methods, and it must return a const sf::Input&

Upvotes: 1

Views: 1052

Answers (3)

user213313
user213313

Reputation:

You could perhaps have the Singleton constructor set the instance pointer, i.e.

Singleton::Singleton()
{
    assert(instance == nullptr);
    instance = static_cast<T*>(this);
}

You can then remove the setInstance function from the interface and getInstance can simply return instance.

In response to the comment, I was assuming that classes were being defined like this:

class MyClassThatShouldBeASingleton : public Singleton<MyClassThatShouldBeASingleton>
{
};

Of course, this does mean that you need to explicitly set up such a singleton rather than it instantiating automatically as in the original code. It's not necessarily how you'd want all singletons to work, just one way of solving the problem.

Upvotes: 1

Adrian McCarthy
Adrian McCarthy

Reputation: 47962

You're invoking the default constructor in getInstance with:

instance = new T;

What do you expect to happen if someone calls getInstance before setInstance?

If it's an error to call getInstance before setInstance, then getInstance should assert or throw or return NULL if called before instance is set. Just get rid of the new T, and your code will compile.

If it's not an error to call getInstance before setInstance, then you don't really have a singleton. Early callers would receive a default constructed object and later callers would get the one set later. That's two instances and therefore not a singleton.

Upvotes: 2

Mike Seymour
Mike Seymour

Reputation: 254461

If you have a reference member, then you cannot (sensibly) make your class default-constructible or assignable, since references must be initialised, and can't be reassigned.

If you need those properties from the class, then you probably want the member to be a pointer, initialised to null by default and assignable later if needed.

Upvotes: 2

Related Questions