什么是预期的行为?

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是错误的.那是对的吗?

Joh*_*itb 2

我不认为这些都是不规范的。首先,using X::f2查找X, ,这将明确产生类类型X。然后查找f2in ,这也是明确的(它不是在 in 中查找的)XD ,这也是明确的(它不是在 中查找!)。

\n

出于同样的原因,第二种情况也会起作用。

\n

但是,如果您调用 f2一个D对象,则该调用将是不明确的,因为该名称会在类型f2的所有子对象中查找,并且有两个这样的子对象,并且是一个非静态成员函数。同样的原因也适用于第二种情况。无论您使用还是直接命名,这都没有什么区别。这两个都指定了类DXDf2f3Z::XXX

\n

为了使 using 声明具有歧义,您需要以不同的方式编写它。请注意,在 C++0x 中using ThisClass::...;无效。但在 C++03 中,只要整个名称引用基类成员即可。

\n

相反,如果 C++0x 中允许这样做,则整个 using 声明也将有效,因为 C++0x 在名称查找时不考虑子对象:D::f2明确仅引用一个声明( 中的声明X)。请参阅DR #39和最终论文N1626

\n
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};\n
Run Code Online (Sandbox Code Playgroud)\n

C++03 标准在10.2和段落中对此进行了描述3.4.3.1

\n
\n

对 Edit3 的回复

\n

是的,GCC和VS2010都是错误的。trouble指的是通过注入的类名找到的类型,::trouble以及找到的嵌套类Y::trouble。使用非限定查找(by trouble,在第一个项目符号中委托给 to )来查找前面的名称,忽略任何对象、函数和枚举器名称( - 但在本例中没有这样的名称)。它违反了\ 的要求:::3.4.1/710.23.4.3/110.2

\n
\n

如果生成的声明集并非全部来自同一类型的子对象……则程序格式错误。

\n
\n
\n

VS2010 和 GCC 对 C++0x 措辞的解释可能与 Comeau 不同,并追溯实现该措辞:

\n
\n

在用作成员声明的 using 声明中,嵌套名称说明符应命名所定义的类的基类。

\n
\n

这意味着会考虑非基类,但如果命名非基类则会出错。如果标准打算忽略非基类名称,它会说只能在这里,或者明确地拼写出来(两种做法都已完成)。然而,该标准并不因使用“ shall”“can”而产生。GCC 实现了 C++0x 措辞,因为它拒绝其他完全良好的 C++03 代码,只是因为 using 声明包含其类名。

\n

对于措辞不明确的示例,请考虑以下表达式:

\n
a.~A();\n
Run 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
\n

这是错误的用法,因为它根本无法消除歧义。它应该使用“can only”,并且编译器以这种方式解释它。正如一些委员会成员最近在新闻组上告诉我的那样,这主要是历史原因。参见国际标准的结构和起草规则,附录 H。

\n