Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling a static method by repeating the object name?

Tags:

c++

c++11

I have a singleton:

struct foo {   static foo& instance() {     static foo f;     return f;   } }; 

When re-arranging some code I ended up with this statement "by error":

foo::foo::instance() 

But this is deemed correct by my compiler (gcc 4.7). In fact, even foo::foo::foo::instance() compiles. Why?

like image 643
piwi Avatar asked Nov 26 '14 15:11

piwi


2 Answers

It is due to "injected-name" — which means if foo is a class-name, and the same name "foo" is also injected into the class-scope which is why your code works. It is 100% Standard-conformant.

Here is one interesting example which shows the benefits of this feature:

namespace N {    //define a class here    struct A     {         void f() { std::cout << "N::A" << std::endl; }    }; }  namespace M {    //define another class with same name!    struct A     {         void f() { std::cout << "M::A" << std::endl; }    };     struct B : N::A  //NOTE : deriving from N::A    {          B()          {             A a;             a.f(); //what should it print?          }    }; } 

What should a.f() call? What is the type of a? Is it M::A or N::A? The answer is, N::A, not M::A.

  • Online Demo

It is because of name-injection, N::A is available inside the constructor of B without qualification. It also hides M::A, which remains outside the scope of B. If you want to use M::A, then you've to write M::A (or better ::M::A).

like image 167
Nawaz Avatar answered Oct 03 '22 22:10

Nawaz


Because of [class]/2:

A class-name is inserted into the scope in which it is declared immediately after the class-name is seen. The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name.

So foo::foo is an injected class name, denoting foo itself.


Actually it's a bit more complicated: according to [class.qual]/2, foo::foo alone denotes a constructor of foo. In order to denote a class, it should either be preceded by struct (making it elaborated-type-specifier), or followed by :: (making it a nested-name-specifier - this is your case), or be a base-specifier (for example struct bar : foo::foo {};).

like image 26
Anton Savin Avatar answered Oct 03 '22 23:10

Anton Savin