这是一些人为的示例代码:
template<typename T> void Do(T arg) { (void)arg->b; }
namespace A {
struct Foo { int a; };
}
namespace B {
struct Foo { int b; };
struct Bar : A::Foo {
void Blah() { Do((Foo *)0); }
};
}
Run Code Online (Sandbox Code Playgroud)
哪个用gcc 4.8.2编译时(clang给出了类似的错误):
namespacebug.cpp: In instantiation of ‘void Do(T) [with T = A::Foo*]’:
namespacebug.cpp:10:34: required from here
namespacebug.cpp:1:39: error: ‘struct A::Foo’ has no member named ‘b’
template<typename T> void Do(T arg) { (void)arg->b; }
^
Run Code Online (Sandbox Code Playgroud)
请注意,它引用的错误T = A::Foo即使在调用站点我正在创建一个Foo内部命名空间B.如果我删除基类decl(: A::Foo)然后所有编译都很好.
这似乎表明从A::Foo某种方式继承将其带入我的命名空间并将其与我的使用相匹配Foo?什么C++"功能"导致了这个?
(当然,这个问题可以通过命名空间我的使用轻松解决Foo,但这不是问题.)
由于inject-class-name规则,类的名称可见,就像它是成员一样.
9/2
一个类名被插入在其中后立即宣布的范围类的名字能够被看见.的类名也被插入到类本身的范围; 这被称为注入类名.出于访问检查的目的,inject-class-name被视为公共成员名称.
因此,类似于A::Foo包含一个Foo命名该类型的成员A::Foo.由于名称查找Bar::Blah()考虑了Bar之前名称空间成员的基本成员,因此名称查找用于Foo查找注入的类名称,即名称A::Foo.