2012-06-20 14 views
18

espero que el título describe realmente lo que quería preguntar ...C++ llamada al método de resolución de alcance y tipo de ambigüedad

yo escribimos un trozo de código que compila con gcc y trabaja como era mi intención. Sin embargo, no se compila con llvm y el código se ejecuta de manera diferente cuando se compila con icc!
Aquí se muestra un ejemplo del problema:

#include <iostream> 

using std::cout; using std::endl; 

class A { 
public: 
    virtual void foo() { cout << "A::foo()" << endl; } 
}; 

class B : public A { 
public: 
    typedef A base; 
    virtual void foo() { cout << "B::foo()" << endl; } 
}; 

int main() { 
    typedef B base; 
    base* bp = new B(); 
    bp->base::foo(); 
} 

salida de gcc: A :: foo()
ICC de salida: B :: foo()

Podría explicar a alguien lo que hace la norma dicen acerca ¿este caso?

+5

Diría que es un error en GCC e ICC, ya que 'B :: base' no es un _miembro de' B', lo que significa que no debería ser posible acceder a él como miembro ('bp-> base'). –

+1

Estoy de acuerdo con @JoachimPileborg, además 'base' podría interpretarse como B en este ámbito. ¿Has compilado con banderas de Advertencias? (-Wall for gcc) – Geoffroy

+1

¿No es solo un comportamiento indefinido, porque 'main' no tiene la forma requerida? Parece que todos los compiladores tienen razón. –

Respuesta

7

De C++ 11, §3.4.5/4:

Si la expresión-id en un acceso de miembro de clase es un id-calificado del formulario
 
    class-name-or-namespace-name::... 
el nombre-clase-o-nombre-nombre-nombre que sigue al. o -> el operador se busca por primera vez en la clase de la expresión del objeto y se utiliza el nombre, si se encuentra. De lo contrario, es buscado en el contexto de toda la expresión postfix.

No creo que pueda ser más claro. Esto encuentra B::base, por lo que la salida debe ser A::foo().

+0

Gracias por la ayuda, ustedes son geniales. ¡Este párrafo en particular es realmente muy claro y exactamente al punto! – Nowakus

6

Creo que esta parte de la norma es relevante:

3.4.3.1 miembros de la Clase [class.qual]

1) Si el anidado de nombre especificador de un cualificado-id designa a un clase, el nombre especificado después del especificador de nombres anidados se busca en el alcance de la clase (10.2), excepto en los casos enumerados a continuación. El nombre representará uno o más miembros de esa clase o de una de sus clases base (Cláusula 10). [Nota: se puede hacer referencia a un miembro de la clase usando un ID calificado en cualquier punto en su alcance potencial (3.3.7). nota -fin] Las excepciones a la regla búsqueda de nombre anterior son los siguientes:

- un nombre destructor se miraron hacia arriba como se especifica en 3.4.3;

- una conversión-id-tipo de un conversión-id-función se busca de la misma manera que un id-conversión-tipo en un acceso de miembro de clase (ver 3.4.5);

- los nombres en una plantilla-argumento de un template-id se buscan en el contexto en el que se produce toda la expresión de postfijo.

- la búsqueda de un nombre especificado en una declaración de uso (7.3.3) también encuentra nombres de enumeración de clase o ocultos dentro del mismo ámbito (3.3.10).

base:: en este caso parece que "nominar" una clase, por lo que el aspecto de seguridad se realizan en el ámbito de la clase. No veo cómo podría aplicarse ninguno de los casos de excepción, por lo que es el alcance de la clase, como tal base es equivalente a A.

(5.1.1-8 indica que es un calificado-id en ese caso y que 3.4.3.1 aplica)

+0

De acuerdo. Me parece bastante claro también. El código es correcto, está bien definido y la salida debe ser 'A :: foo'. –

Cuestiones relacionadas