通过重复对象名称调用静态方法?

piw*_*iwi 46 c++ c++11

我有一个单身人士:

struct foo {
  static foo& instance() {
    static foo f;
    return f;
  }
};
Run Code Online (Sandbox Code Playgroud)

在重新安排一些代码时,我最终得到了"错误"这句话:

foo::foo::instance()
Run Code Online (Sandbox Code Playgroud)

但是我的编译器认为这是正确的(gcc 4.7).事实上,甚至foo::foo::foo::instance()编译.为什么?

Naw*_*waz 45

这是由于"注入名称" - 这意味着if foo是一个类名,并且同样名称"foo"也被注入到类范围中,这就是代码工作的原因.它符合标准100%.

这是一个有趣的例子,展示了这个功能的好处:

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?
         }
   };
}
Run Code Online (Sandbox Code Playgroud)

该怎么a.f()称呼?是什么类型的a?难道M::A还是N::A?答案是N::A,不是M::A.

这是因为名称注入,N::AB没有资格的构造函数内可用.它也隐藏 M::A,但仍然不在范围内B.如果你想使用M::A,那么你要写M::A(或更好::M::A).


Ant*_*vin 21

因为[class]/2:

一个类名被插入在其中后立即宣布的范围类的名字能够被看见.的类名也被插入到类本身的范围; 这被称为注入类名.

所以foo::foo是一个注入的类名,表示foo本身.


实际上它有点复杂:根据[class.qual]/2,foo::foo单独表示一个构造函数foo.为了表示一个类,它应该在struct(使其成为详细类型说明符)之后,或者后面跟着::(使它成为嵌套名称说明符 - 这是你的情况),或者是一个基本说明符(对于例子struct bar : foo::foo {};).


Lor*_*ins 11

如其他答案中所述,原因是名称注入.对我来说,主要用例如下

struct B1 { void f(){} };
struct B2 { void f(){} };

struct D : B1, B2 { }

int main() {
    D obj; 
    obj.f(); 
}
Run Code Online (Sandbox Code Playgroud)

main调用f是模糊的,不会编译.具体的方式是合格的呼叫,即

obj.B1::f(); 
Run Code Online (Sandbox Code Playgroud)

  • 但是,`obj.B1 :: f`不使用注入的名称. (2认同)