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

时间:2014-11-26 15:07:44

标签: c++ c++11

我有一个单身人士:

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

当重新安排一些代码时,我最终得到了这个陈述"错误":

foo::foo::instance()

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

3 个答案:

答案 0 :(得分:45)

这是由于“注入名称” - 这意味着如果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?
         }
   };
}

a.f()应该叫什么? a的类型是什么?是M::A还是N::A?答案是N::A,而不是M::A

由于名称注入,N::AB的构造函数中没有限定条件。它还隐藏 M::A,这仍然在B的范围之外。如果您想使用M::A,那么您需要撰写M::A(或更好::M::A)。

答案 1 :(得分:21)

由于[class]/2

  

class-name 被插入到在看到 class-name 之后立即声明它的范围内。 class-name 也会插入到类本身的范围内;这被称为 inject-class-name

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


实际上它有点复杂:根据[class.qual]/2foo::foo单独表示foo的构造函数。为了表示一个类,它应该以{{1​​}}开头(使其成为 elaborated-type-specifier ),或者后跟struct(使其成为嵌套名称说明符 - 这是您的情况),或者是基本说明符(例如::)。

答案 2 :(得分:11)

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

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

struct D : B1, B2 { }

int main() {
    D obj; 
    obj.f(); 
}

main中,f的调用不明确,无法编译。具体的方式是合格的呼叫,即

obj.B1::f();