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

我有一个单身人士:

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

当重新安排一些代码时,我以“错误”结束了这个陈述:

 foo::foo::instance() 

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

这是由于“注入名称” – 这意味着如果foo是一个类名称,并且同样的名字“foo”也被注入到类的范围内,这就是为什么你的代码工作。 这是100%符合标准。

下面是一个有趣的例子,它显示了这个function的好处:

 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; af(); //what should it print? } }; } 

af()应该调用什么? 什么是一个types? 是M::A还是N::A ? 答案是, N::A ,而不是M::A

  • 在线演示

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

由于[class]/2

在看到类名后立即声明一个类名类名也被插入到类本身的范围中; 这被称为注入类的名称

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


其实它有点复杂:根据[class.qual]/2foo::foo单独表示foo::foo的构造函数。 为了表示一个类,它应该在struct前面(使它具有详细的types说明符 ),或者跟在:: :(使它成为一个嵌套的名称说明符 – 这是你的情况) 说明符 (例如, struct bar : foo::foo {}; )。

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

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

main调用f是不明确的,不会编译。 具体的方式是一个合格的电话,即

 obj.B1::f();