danielspaniol
danielspaniol

Reputation: 2328

C++ Singleton #define

I have a small question to the singleton pattern using C++. Let's say I have the following class:

namespace MyNameSpace 
{
   class Window_Singleton 
   {
   private:
      static Window_Singleton instance;
      Window_Singleton();
      /* Some more private stuff here */

   public:
      static Window_Singleton *GetInstance();
      ~Window_Singleton();
      /* Some more public stuff here */

   }
}

#define Window Window_Singleton.GetInstance()

I have this #define so that I don't always have to write MyNameSpace::Window_Singleton.GetInstance().SomeMethod(), I can now use the shorter MyNameSpace::Window.SomeMethod().

But the problem is: Now I cannot make a Window-class in another namespace because I will get problems with the define.

Is there a way to provide the #define without "breaking" my namespace. Some sort of "namespace-local" define?

Upvotes: 0

Views: 1082

Answers (4)

2785528
2785528

Reputation: 5566

I think there is not a way to use a macro, which ignores scope rules.

You might consider a typedef:

namespace MyNameSpace 
{
   class Window_Singleton 
   {
   // ...
   };

   typedef Window_Singleton  WS;

// ...
}

Your code can now use the typedef'd synonym / alias ...

// WS is alias/synonym for Window_Singleton
MyNameSpace::WS::SomeMethod();   // access to static method

MyNameSpace::WS  ws;   // declare instance
ws.SomeMethod2();       // access instance

Hint - I try to limit namespace names to 3 letters. Consider

namespace ETB;  // for Exhauzt Tool Box

or

namespace EWS;  // for Exhauzt Window Singleton 

Upvotes: 0

Christian Hackl
Christian Hackl

Reputation: 27538

Is there a way to provide the #define without "breaking" my namespace. Some sort of "namespace-local" define?

Short answer: No.


Longer answer: Macros have no scope. That's what's sets them apart from other C++ features, for better or worse.


Complete answer:

  • Don't use macros if you can avoid it.
  • Use ALL_CAPS if you use any macro.
  • Don't use the Singleton pattern at all.
  • Easy writing is not a relevant factor in code quality.

A note on the last point: if you are concerned about MyNameSpace::Window_Singleton.GetInstance().SomeMethod() being too long to read, then I can certainly sympathise with that. But that's still not a reason to infest your code with macros. You should instead use using at local scope, a reference and possibly auto to increase readability. Example:

void f()
{
    using MyNameSpace::Window_Singleton;
    auto& window = Window_Singleton.GetInstance();

    window.SomeMethod();
}

Upvotes: 1

463035818_is_not_an_ai
463035818_is_not_an_ai

Reputation: 122830

I strongly suggest you not to use a #define here. It actually does not spam the namespace but it can completele mess up any code that includes this define with hard to find errors. For example, once the symbol Window is defined, a function

Foo(Bar* Window){ /*...*/}

is broken and in some cases you will have a hard time to spot such errors. Further it makes your code much harder to read. If I want to call a static function to get an instance and call a method, I expect the code to look like this:

Window_Singleton::GetInstance().SomeMethod();

while

Window.SomeMethod();

looks more like calling the method of some global instance. I mean you could use a global

Window_Singleton Window;

but as I understood, you dont want to use a global for the singleton. In summary: your code is easy to read if it reflects what you actually want to do. Calling a static method is least obfuscated when it looks like calling a static method. If you are lazy to type, use some editor with code completition, but dont make your code harder to read by using potentially dangerous defines.

PS: I have to mention that in my comments I was a bit confused. #defines are completely unaware of namespaces. They are replacedin the code, before the compiler starts the actual work. Thats why it can be hard (if not impossible) to relate compiler errors caused by #defines to the place where the symbol was defined.

Upvotes: 1

Anedar
Anedar

Reputation: 4275

As macros are expanded way before the compilation, the precompiler is not aware of things like classes, namespaces and so on. So no, if you define a macro Window it will be used everywhere.

What you could do is define a function:

inline Window_Singleton& Window(){
  return Window_Singleton.GetInstance();
}

and then write

Window().SomeMethod();

It's basically an additional pair of braces, but it will keep your code a lot clearer.

Upvotes: 2

Related Questions