Chu*_*dad 7 c++ using declaration ambiguity
以下是纯粹学术上发明的类层次结构.
struct X{
void f1();
void f2();
void f3();
};
struct Y : private X{
void f4();
};
struct Z : X{
};
struct D : Y, Z{
using X::f2;
using Z::X::f3;
};
int main(){}
Run Code Online (Sandbox Code Playgroud)
我期望使用X :: f2的声明是模糊的,因为'X'是'D'的可模糊基础(可见性与X的可访问性).但是g ++(ideone.com)编译得很好.
我使用Online Comeau进行了检查,并且在预期使用X :: f2的声明时出错.但是,它也为使用Z :: X :: f3的声明提供了歧义.
那么预期的行为是什么?
编辑1:
请参考标准的相应部分.
编辑2:
我查看了VS 2010,它只对使用声明X :: f2提出异议.然而,它不是关于'X'的歧义(如gcc和Comeau的情况).这是关于"错误C2876:'X':并非所有重载都可以访问".
编辑3:
struct X{
void f(){}
};
struct Y : X{
struct trouble{
void f(){}
};
};
struct trouble : X{
};
struct letscheck : Y, trouble{
using trouble::f;
};
int main(){}
Run Code Online (Sandbox Code Playgroud)
在这里,我尝试(有目的地)使用声明创建类型的问题.Gcc仍然编译这个罚款,VS2010也是如此.Comeau仍然会出现关于模糊类型'麻烦'的错误(正如预期的那样).通过对初始查询给出的解释,看起来GCC和VS2010是错误的.那是对的吗?
我不认为这些都是不规范的。首先,using X::f2查找X, ,这将明确产生类类型X。然后查找f2in ,这也是明确的(它不是在 in 中查找的)XD ,这也是明确的(它不是在 中查找!)。
出于同样的原因,第二种情况也会起作用。
\n但是,如果您调用 f2一个D对象,则该调用将是不明确的,因为该名称会在类型f2的所有子对象中查找,并且有两个这样的子对象,并且是一个非静态成员函数。同样的原因也适用于第二种情况。无论您使用还是直接命名,这都没有什么区别。这两个都指定了类DXDf2f3Z::XXX。
为了使 using 声明具有歧义,您需要以不同的方式编写它。请注意,在 C++0x 中using ThisClass::...;无效。但在 C++03 中,只要整个名称引用基类成员即可。
相反,如果 C++0x 中允许这样做,则整个 using 声明也将有效,因为 C++0x 在名称查找时不考虑子对象:D::f2明确仅引用一个声明( 中的声明X)。请参阅DR #39和最终论文N1626。
struct D : Y, Z{\n // ambiguous: f2 is declared in X, and X is a an ambiguous base class\n using D::f2;\n \n // still fine (if not referred to by calls/etc) :)\n using Z::X::f3;\n};\n\nstruct E : D {\n // ambiguous in C++03\n // fine in C++0x (if not referred to by an object-context (such as a call)).\n using D::f2;\n};\nRun Code Online (Sandbox Code Playgroud)\nC++03 标准在10.2和段落中对此进行了描述3.4.3.1。
对 Edit3 的回复:
\n是的,GCC和VS2010都是错误的。trouble指的是通过注入的类名找到的类型,::trouble以及找到的嵌套类Y::trouble。使用非限定查找(by trouble,在第一个项目符号中委托给 to )来查找前面的名称,忽略任何对象、函数和枚举器名称( - 但在本例中没有这样的名称)。它违反了\ 的要求:::3.4.1/710.23.4.3/110.2
\n\n如果生成的声明集并非全部来自同一类型的子对象……则程序格式错误。
\n
VS2010 和 GCC 对 C++0x 措辞的解释可能与 Comeau 不同,并追溯实现该措辞:
\n\n\n在用作成员声明的 using 声明中,嵌套名称说明符应命名所定义的类的基类。
\n
这意味着会考虑非基类,但如果命名非基类则会出错。如果标准打算忽略非基类名称,它会说只能在这里,或者明确地拼写出来(两种做法都已完成)。然而,该标准并不因使用“ shall”和“can”而产生。GCC 实现了 C++0x 措辞,因为它拒绝其他完全良好的 C++03 代码,只是因为 using 声明包含其类名。
\n对于措辞不明确的示例,请考虑以下表达式:
\na.~A();\nRun Code Online (Sandbox Code Playgroud)\n这在语法上是不明确的,因为如果是一个类对象,它可以是一个成员函数调用,但如果它是一个标量类型(例如a),它可以是一个伪析构函数调用(这是一个无操作)。但标准所说的是伪析构函数调用和类成员访问的语法分别为和aint5.2.45.2.5
\n\n点运算符的左侧应为标量类型。
\n对于 \xef\xac\x81rst 选项(点),\xef\xac\x81rst 表达式(对象表达式)的类型应为 \xe2\x80\x9cclass object\xe2\x80\x9d (完整类型)。
\n
这是错误的用法,因为它根本无法消除歧义。它应该使用“can only”,并且编译器以这种方式解释它。正如一些委员会成员最近在新闻组上告诉我的那样,这主要是历史原因。参见国际标准的结构和起草规则,附录 H。
\n| 归档时间: |
|
| 查看次数: |
635 次 |
| 最近记录: |