我有一个单身人士:
struct foo {
static foo& instance() {
static foo f;
return f;
}
};
当重新安排一些代码时,我最终得到了这个陈述"错误":
foo::foo::instance()
但我的编译器认为这是正确的(gcc 4.7)。事实上,甚至foo::foo::foo::instance()
编译。为什么呢?
答案 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::A
在B
的构造函数中没有限定条件。它还隐藏 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]/2
,foo::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();