2010-08-23 17 views
7

A continuación se muestra una jerarquía de clases puramente académicamente inventada.¿cuál es el comportamiento esperado?

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(){} 

que esperaba declaración using para X :: f2 para ser ambiguo como 'X' es una base ambigua de 'D' (vs visbility accesibilidad de X). Sin embargo, g ++ (ideone.com) lo compila bien.

Comprobé con Comeau en línea y da error al usar declaración para X :: f2 como se esperaba. Sin embargo, da ambigüedad para usar la declaración para Z :: X :: f3 también.

¿Cuál es el comportamiento esperado?

Edición 1:

Una referencia a la sección correspondiente de la Norma sería útil, por favor.

Edición 2:

he comprobado con VS 2010 y tiene objeciones solamente con la declaración using X :: f2. Sin embargo, no se trata de la ambigüedad de 'X' (como en el caso de gcc y Comeau). Se trata del "error C2876: 'X': no ​​todas las sobrecargas están accesibles".

Datos 3:

struct X{ 
    void f(){} 
}; 

struct Y : X{ 
    struct trouble{ 
     void f(){} 
    }; 

}; 

struct trouble : X{ 
}; 

struct letscheck : Y, trouble{ 
    using trouble::f; 
}; 

int main(){} 

Aquí he intentado (a propósito) para crear un problema con los tipos en el uso de la declaración. Gcc todavía compila esta multa y también lo hace VS2010. Comeau todavía da error (como se esperaba) sobre tipos ambiguos 'problema'. Siguiendo las explicaciones dadas para las consultas iniciales, parece que GCC y VS2010 están equivocados. ¿Es eso correcto?

+0

En D, agregue un método que llame a f2() vea qué sucede. –

Respuesta

2

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.

+0

@litb: Modifiqué la clase 'D' de la siguiente manera: struct D: Y, Z {usando X :: f2; usando Z :: X :: f3; void f() {X * p = this;}}; Ahora recibí el error prog.cpp: 19: error: repetido usando la declaración 'using X :: f3' prog.cpp: en la función miembro 'void D :: f()': prog.cpp: 20: error: 'X 'es una base ambigua de' D ' Son las reglas diferentes para' usar declaración 'durante' buscar nombre ' – Chubsdad

+0

@chubsdad todo lo que puedo hacer es repetir el Estándar. No sé qué implementan esos compiladores. No veo una "declaración de uso repetido" en su código. –

+0

@litb: un ligero error tipográfico en mi código y, por lo tanto, la salida del compilador.El error revisado sigue: prog.cpp: En la función miembro 'void D :: f()': prog.cpp: 20: error: 'X' es una base ambigua de 'D' – Chubsdad

0

usando X :: f2; no debe trabajar debido a la herencia privada de código a continuación

struct Y : private X{ 
    void f4(); 
}; 

No es posible acceder a los miembros de X a Y. Así X :: f2 haría conflictos.

Z::X::f2 debería funcionar. O Z::f2 debería funcionar.

+0

C++ tiene la regla de acceso múltiple. Si se puede encontrar un nombre por varias rutas en una jerarquía de clases base, y una de ellas es pública, se toma esa ruta de acceso público. Ver '11.7/1'. –

+0

@litb: Significa que 'usar X :: f2' está bien ya que 'X' es accesible a través de 'Z' en OP. Pero entonces 'X' es ambiguo y, por lo tanto, el error relacionado con la ambigüedad. Por lo tanto, el mensaje de error VS2010 sobre 'no todas las sobrecargas son accesibles' es probablemente complicado. Esto significa que Comeau tiene razón. Por lo menos, sospeché el error sobre el uso de la declaración para 'Z :: X :: f3'. – Chubsdad

+0

@chubsdad solo significa que no es un error de accesibilidad. Cambia el acceso a la ruta que brinda más acceso. No sería una búsqueda ambigua incluso sin 11.7/1, pero entonces no sabríamos si necesitamos aplicar accesibilidad privada o pública. –

0

Primero, para aclarar la respuesta de Johannes. Cuando dice using Z::X::f2;, el compilador no "crea una ruta" al f2 para realizar un seguimiento de cómo se debe acceder. Dado que Z::X es lo mismo que X, la declaración es exactamente igual a decir using X::f2;. Contrastarlo con este ejemplo:

struct A { void f() {} void g() {} }; 
struct B { void f() {} void g() {} }; 
struct C { typedef A X; }; 
struct D { typedef B X; }; 
struct E : A, B { 
    using C::X::f; // C::X == A 
    using D::X::g; // D::X == B 
}; 

La sintaxis Z::X funciona no por herencia o adhesión, pero debido a que el identificador X es accesible desde el ámbito Z. Incluso puede escribir Z::Z::Z::Z::X::X::X::X ad nauseam, porque cada clase trae su propio nombre en su propio ámbito. Por lo tanto :: aquí no expresa la herencia.

Ahora, para resolver el problema. f2 es heredado por Y y Z desde X. Por lo tanto, es un miembro de primera clase de Y y Z. E no necesita saber acerca de X porque es un detalle de implementación oculto. Por lo tanto, desea

struct D : Y, Z{ 
    using Y::f2; // error: inaccessible 
    using Z::f3; 
}; 

Para explicar en términos de 9.1/2 cuando pregunte:

A class-name is inserted into the scope in which it is declared immediately after the class-name is seen. The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name.

El nombre X se inyecta en X como X::X. A continuación, se hereda en Y y Z. Y y Z no declaran implícitamente X en su propio ámbito.

10,2/2:

The following steps define the result of name lookup in a class scope, C. First, every declaration for the name in the class and in each of its base class sub-objects is considered. … If the resulting set of declarations are not all from sub-objects of the same type, or the set has a nonstatic member and includes members from distinct sub-objects, there is an ambiguity and the program is ill-formed. Otherwise that set is the result of the lookup.

Nota que en negrita las palabras en plural sub-objetos. Aunque el nombre X se encuentra en dos subobjetos, ambos son del mismo tipo, es decir, X.

+0

Dentro del alcance de 'D', hay dos suboobjetos 'X' (uno de 'Y' (inaccesible) y otro de ' Z '(accesible)). Con referencia a $ 9.2 (nombre de clase inyectado). ¿No debería ser' ambiguo usar X :: f2 'con la lógica anterior ya que' X 'es una base ambigua de' D '? – Chubsdad

+0

@chubs: Solo hay una clase llamada 'X'.' X' nombra una clase, no un subobjeto: ese es el punto de mi enfermedad ustration. – Potatoswatter

+0

@chubs: como para §9.1/2 (no $ 9.2), vea la respuesta actualizada. – Potatoswatter

Cuestiones relacionadas