Calling a static method by repeating the object name?

后端 未结 3 1370
-上瘾入骨i
-上瘾入骨i 2020-12-15 15:14

I have a singleton:

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

When re-arranging some code I ended

相关标签:
3条回答
  • 2020-12-15 15:38

    As stated in the other answers, the reason is name injection. To me, the main use case would be the following

    struct B1 { void f(){} };
    struct B2 { void f(){} };
    
    struct D : B1, B2 { }
    
    int main() {
        D obj; 
        obj.f(); 
    }
    

    In main the call to f is ambiguous and won't compile. The way to be specific is a qualified call, ie

    obj.B1::f(); 
    
    0 讨论(0)
  • 2020-12-15 15:39

    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 {};).

    0 讨论(0)
  • 2020-12-15 15:58

    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).

    0 讨论(0)
提交回复
热议问题