C++ C++;
第一组类声明(C++ C++;,c++,c++11,c++14,member,c++03,C++,C++11,C++14,Member,C++03,第一组类声明(A,B,C和D)和第二组(W,X,Y和Z)的构建方式类似,只是类C有一个使用声明(使用A::A),而类Y没有 当试图访问d.a=0中的成员a时,我在Clang(错误:在不同类型的多个基类中找到了成员“a”)和GCC(错误:对成员“a”的请求不明确)。我检查了这两个编译器的最新版本和旧版本,他们都同意。但是,在z.w=0中访问w会成功编译 访问a时出现这种歧义的原因是什么 据我所知,类B和C中的访问声明都引用同一个基类成员。顺便说一下,如果我删除它们,测试将成功编译,因为a已经可以公
A
,B
,C
和D
)和第二组(W
,X
,Y
和Z
)的构建方式类似,只是类C
有一个使用声明(使用A::A
),而类Y
没有
当试图访问d.a=0中的成员a
时,我在Clang(错误:在不同类型的多个基类中找到了成员“a”)和GCC(错误:对成员“a”的请求不明确
)。我检查了这两个编译器的最新版本和旧版本,他们都同意。但是,在z.w=0
中访问w
会成功编译
访问a
时出现这种歧义的原因是什么
据我所知,类B
和C
中的访问声明都引用同一个基类成员。顺便说一下,如果我删除它们,测试将成功编译,因为a
已经可以公开访问(public
access说明符)
提前谢谢
注意:上面的代码是对“SuperTest套件”稍加修改的测试。此处存在实现差异;ICC接受您的代码,而gcc、clang和MSVC拒绝您的代码。ICC是正确的,而其他编译器是不正确的
运行D::a
的算法,我们发现:
- 在
D
中没有a
的声明,因此S(a,D)最初是空的,我们在a
的基类中合并查找集,计算如下:
- S(a,B)={a::a},{B}
- S(a,C)={a::a},{C}
- 结果查找集是S(a,D)={a::a},{B,C}
请注意,在S(a,B)的声明集中,成员是a::a
,即使它位于B
中,对于S(a,C)也是如此:
在声明集中,使用声明将替换为指定成员集[…]
为了确定成员访问d.a
是否不明确,我们现在检查[expr.ref]/5:
5-[code]如果E2
直接作为成员的类是E2
[…]命名类的模糊基,则程序是格式错误的
在这里,E2
被确定为A::A
,A
的直接成员。命名类是D
A
不是D
的模糊基,因为A
是D
的所有中间基类子对象的虚拟基。因此,d.a
在名称查找和成员访问方面都是明确的,并且您的程序是正确的
作为一个类似的实例,我们可以考虑用一个静态成员替换虚拟继承,以[Cal.Actudio.LoopUp] / 9:
9-[ 注意:即使一个对象有多个T
类型的基类子对象,也可以明确地找到基类T
中定义的静态成员、嵌套类型或枚举数。两个基类子对象共享其公共虚拟基类的非静态成员子对象- 尾注 ]
这里我们还有S(a,D)={{a::a},{B,C}。事实上,即使a::a
是非虚拟基的非静态成员,名称查找也是以同样的方式进行的;名称查找是明确的,但在这种情况下,成员访问[expr.ref]是不明确的
为了进一步说明名称查找和成员访问之间的区别,考虑到即使对于非虚拟多重继承基类的非静态数据成员,也可以明确地使用派生类的成员的名称作为命名类:
struct A { static int a; };
struct B : A { using A::a; };
struct C : A { using A::a; };
struct D : B, C { };
int main() {
D d;
d.a = 0; // OK
}
不幸的是,我尝试过的每一个编译器都拒绝了这一点,尽管这是(使用声明的模)!d.a
可以在d.B::a
和d.C::a
之间进行选择(即使在现实中也有相同的选择)。为什么不使用d.A::A=0;
?我在这里找不到任何使用的文档(只有别名和与命名空间相关的用法)成员访问规则在C++ 11中被更改。根据我所看到的,您的示例对于C++ 11完全有效。C++ 03规则,我认为您的第一个代码不正确,因为它不考虑使用透明声明(查找不针对C++ 03查看):它会找到“W”。在B和C中,两者都不占优势。对于第二个测试用例,它在w和X中找到“w”,但X比w占优势,因此X获胜。在C++11中,在这两个测试用例中,它都找到“w”分别在W和A中,没有歧义。@jos是的,所以我不知道,在C++03中似乎也是有效的。另一方面,它并没有说两个使用声明合并了。它只说这两个都被认为来自同一子对象(为了这两个检查的目的)。因此名称查找仍然会找到两个声明。也许这就是编译器抱怨的原因?您的答案的最后一部分是声称实现C++11的现有实现存在的一个长期问题,另请参见10.2规则中有关重载解析的措辞不明确。所有这些都没有得到解决ved(据我所知)尽管我直接向负责人发布了DRs,但无论是在规范中还是在实现中都没有。@ecatmur非常感谢您的解释,我同意代码对C++11和C++14有效。您认为代码对C++03也有效吗?您引用的确切算法尚未定义,只有一段(10.2/2)在[class.member.lookup]中定义这种行为(这里引用了C++03的一段:)@JoséLuis我相信它对C++03也是有效的
struct A { static int a; };
struct B : A { using A::a; };
struct C : A { using A::a; };
struct D : B, C { };
int main() {
D d;
d.a = 0; // OK
}
struct A { int a; };
struct B : A { using A::a; };
struct C : A { using A::a; };
struct D : B, C { };
int B::*p = &D::i; // OK, unambiguous