-1

Everyone knows the singleton pattern (very simple exemple) :

class Singleton
{
private:
    static Singleton* instance;

public:
    static Singleton* GetInstance() { return instance; }

    void Foo() {}
};

And the use :

Singleton::GetInstance()->Foo();

I wonder, why this GetInstance() is mandatory. I've tried to find a way to eliminate the call to this function, to be able to write for exemple... :

Singleton->Foo();

... using the class name the same way I use a variable, because of the singleton pattern, and others security like deleting the public constructor for exemple, we are sure that we only have a single instance, so why not "using the class as a variable" (quote, unquote, only syntaxic speaking of course !).

Each time, a C++ rule prohibit following exemples :

Singleton->Foo(); // (1)
Singleton()->Foo(); // (2)
Singleton.Foo(); // (3)
Singleton::Foo(); // (4)

Because :

  • (1) static Singleton* operator->() { return instance; } is impossible, Class Member Access Operator (->) overload can't be static (see C2801), same for (2) with operator ()
  • (3) and (4) operators . and :: can't be overloaded

Only solution here : Macros, but I'm actually using macros, and I want to find an other way and avoiding macros for this...

It's only a syntaxic interrogation, I'm not here to debate about pros and cons of singletons, but I wonder why C++ permit so many things for simplify the use syntax of users classes with overloads, user literals, and we can't eliminate this little function from the pattern.

I don't expect a solution (but if there is one, it would be great), it's just to understand why, to know if there is a explanation, a design reason, a security reason or anything else !

Thanks in advance !

Monk
  • 49
  • 4
  • 1
    BTW, This method comes strongly recommended: https://stackoverflow.com/a/1008289/3807729 – Galik Nov 11 '18 at 00:54
  • You can hide a singleton with a façade of static class functions, e.g., `static void Foo() { GetInstance()->Foo(); }`, then the callsite would only have to do `Singleton::Foo();` which is pretty close to (4). – Eljay Nov 11 '18 at 00:59
  • @Galik, interesting link, thanks. But i will go a little it further : I understand that this method can be important for destruction explained in your link, and in fact, I do not want to remove it from the class, only from the user code. Admit that operator -> can be static I could write : `static Singleton* operator->() { return GetInstance(); }`, and use `Singleton->Foo();`, the problem is not the existence of the method, but the call to this method in user code ! – Monk Nov 11 '18 at 01:03
  • @Eljay It's what I've thinking, but it mean that we always have to change all methods of all singletons class to statics methods or duplicate all publics methods to get a static version calling a non static version of the method... It's why I just speak of syntax, I don't want to change meaning of the existing code ! – Monk Nov 11 '18 at 01:06
  • There is a different pattern called the Monostate pattern. Very similar to a Singleton. All the functions are static functions ("class functions"), and all the data is in static variables ("class variables"). Any instances are empty, so usage just acts as a proxy for the class functions and class variables. – Eljay Nov 11 '18 at 13:32

2 Answers2

1

Well one way to do this is to reduce the singleton part of the problem to just the data and create static functions that access that data through the "instance" function (called self() in this example):

class Singletonish
{
private:
    // single (inaccessible) instance of the data
    static auto& self()
    {
        static struct {
            std::string s = "unset";
            int i = 0;
        } data;
        return data;
    }

public:

    static void foo()
    {
        // foo code here
        self().s = "hello";
        self().i = 9;
    }

    static void woo()
    {
        // woo code here
        std::cout << self().s << '\n';
        std::cout << self().i << '\n';
    }
};

int main()
{
    Singletonish::woo();

    Singletonish::foo();

    Singletonish::woo();
}

Output:

unset
0
hello
9

Personally I recommend just doing it the normal way: https://stackoverflow.com/a/1008289/3807729

Galik
  • 47,303
  • 4
  • 80
  • 117
  • For the sake of ensuring readability, maintainability, and frankly, *sanity*, I second your closing personal stance. – WhozCraig Nov 11 '18 at 01:19
0

I can think of the following way in C++11:

#include <memory>

struct singleton
{
    int i;
};

template <class Singleton_t> 
struct singleton_holder
{
    auto* operator -> () const noexcept
    {
        static Singleton_t s;
        return std::addressof(s);
    }
};

// optional C++14 feature, can be commented if wanted
template <class Singleton_t>
constexpr const static /* inline */ singleton_holder<Singleton_t> singleton_v{};

Now, with this code, you can just create singleton_holder<singleton> s and use s->i to access the member of the singleton directly.

Or you can use C++14 way: singleton_v<singleton>->i to access member of the singleton directly.

JiaHao Xu
  • 2,452
  • 16
  • 31