Vuwox
Vuwox

Reputation: 2359

C++ Singleton Instance disable re-call

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

Answers (1)

Barry
Barry

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

Related Questions