这是一些人为的示例代码:
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); }
};
}
当用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; }
^
在错误中注意它引用T = A::Foo
,即使在调用站点我在命名空间Foo
内创建B
。如果我删除基类decl(: A::Foo
),那么所有编译都很好。
这似乎表明继承自A::Foo
以某种方式将其带入我的命名空间并将其与我对Foo
的使用相匹配?什么是C ++&#34;功能&#34;导致这个?
(当然,这个问题很容易通过命名空间使用Foo
来修复,但这不是问题。)
答案 0 :(得分:5)
由于注入了类名称规则,类的名称就像是成员一样可见。
9/2
class-name 被插入到在看到 class-name 之后立即声明它的范围内。 class-name 也会插入到类本身的范围内;这被称为 inject-class-name 。出于访问检查的目的,inject-class-name被视为公共成员名称。
因此,类A::Foo
包含一个名为Foo
类型的成员A::Foo
。由于Bar::Blah()
中的名称查找在命名空间成员之前考虑Bar
的基本成员,因此Foo
的名称查找会找到注入的类名,其名称为A::Foo
。
答案 1 :(得分:3)
从类继承是否会将其带入命名空间?
排序。如果在类中查找名称失败,则在基类中继续查找。
10.2会员名称查询
...
5否则(即
C
不包含f
的声明或结果声明集为空),S(f,C)
最初为空。如果C
具有基类,则在每个直接基类子对象f
中计算Bi
的查找集,并合并每个此类查找集S(f,Bi)
反过来进入S(f,C)
。
会员名称查找也包括查找嵌套类型。在同一部分的后面,我们发现:
9 [注意:即使对象具有多个类型为T的基类子对象,也可以明确地找到基类T中定义的静态成员,嵌套类型或枚举器。基类子对象共享其公共虚拟基类的非静态成员子对象。 -end note ]