Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/149.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;_C++_C++11_C++14_Member_C++03 - Fatal编程技术网

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