No creo que ninguno de estos estén mal formados. En primer lugar, para using X::f2
, se busca X
, y esto producirá inequívocamente el tipo de clase X
. Luego se busca f2
en X
, y esto tampoco es ambiguo (¡no se busca en D
!).
El segundo caso funcionará por la misma razón.
Pero si llamadaf2
en un objeto D
, la llamada será ambigua porque el nombre f2
se busca en todos los subobjetos de D
de tipo X
y D
tiene dos de estos objetos parciales, y f2
es un no -esta función de miembro. La misma razón se aplica para el segundo caso. Para esto, no importa si se llama f3
usando Z::X
o X
directamente. Ambos designan la clase X
.
Para obtener una ambigüedad para la declaración de uso, debe escribirla de manera diferente. Tenga en cuenta que en C++ 0x using ThisClass::...;
no es válido. Sin embargo, está en C++ 03, siempre que el nombre completo se refiera a un miembro de la clase base.
Por el contrario, si esto se permitiría en C++ 0x, toda declaración using también sería válida, porque C++ 0x no toma en cuenta los subobjetos para el nombre-de búsqueda: D::f2
se refiere inequívocamente a una sola declaración (el de X
). Consulte DR #39 y el documento final N1626.
struct D : Y, Z{
// ambiguous: f2 is declared in X, and X is a an ambiguous base class
using D::f2;
// still fine (if not referred to by calls/etc) :)
using Z::X::f3;
};
struct E : D {
// ambiguous in C++03
// fine in C++0x (if not referred to by an object-context (such as a call)).
using D::f2;
};
El C++ 03 estándar describe esto en los párrafos 10.2
y 3.4.3.1
.
respuesta para Edit3:
Sí, GCC y VS2010 están equivocados. trouble
se refiere al tipo encontrado por el nombre de clase inyectado de ::trouble
y a la clase anidada encontrada como Y::trouble
. El nombre trouble
se busca usando una búsqueda no calificada (por 3.4.1/7
, que delega en 10.2
en el primer punto) ignorando los nombres de objetos, funciones y enumeradores (3.4.3/1
- aunque en este caso no existen tales nombres). A continuación, viola contra requisito 10.2
's que:
If the resulting set of declarations are not all from sub-objects of the same type ... the program is ill-formed.
Es posible que VS2010 y GCC C++ 0x interpretan de manera diferente a la redacción Comeau y retroactivamente poner en práctica esta fórmula:
In a using-declaration used as a member-declaration, the nested-name-specifier shall name a base class of the class being defined.
Este significa que las clases no básicas son consideradas, pero es un error si se nombra una clase no básica. Si el estándar intentara ignorar los nombres de las clases no básicas, diría que solo puede aquí, o deletérelo explícitamente (ambas prácticas están hechas). Sin embargo, el estándar no es en absoluto consecuente con su uso de será y puede. Y GCC implementa la redacción de C++ 0x, porque rechaza el código C++ 03 por lo demás completamente correcto, simplemente porque la declaración using contiene su nombre de clase.
Para un ejemplo de la redacción poco clara, considere la siguiente expresión:
a.~A();
Ésta es sintácticamente ambigua, ya que puede ser una llamada a la función miembro si a
es un objeto de la clase, pero puede ser un pseudo -destructor-call (que no es operativo) si a
tiene un tipo escalar (como int
). Pero lo que dice la norma es para la sintaxis de una llamada pseudo-destructor y el acceso al miembro de la clase 5.2.4
y 5.2.5
respectivamente
The left-hand side of the dot operator shall be of scalar type.
For the first option (dot) the type of the first expression (the object expression) shall be “class object” (of a complete type).
Ese es el mal uso, ya que no aclara la ambigüedad en absoluto. Debe usar "solo puede", y los compiladores lo interpretan de esa manera. Esto tiene razones principalmente históricas, como me dijo recientemente un miembro del comité en usenet. Ver The rules for the structure and drafting of International Standards, anexo H.
En D, agregue un método que llame a f2() vea qué sucede. –