2012-05-24 49 views
12

Considere el siguiente código:¿Usar el espacio de nombres causa ocultar el nombre?

namespace C { 
    class X {}; 
} 

namespace A { 
    class X {}; 

    namespace B { 
     using namespace C; 

     X x; 
    } 
} 

que estaba esperando el tipo de x ser C::X debido a la Directiva using namespace, pero en su lugar tanto VS2010 y en línea LLVM/Clang determinación compilador X dentro del espacio de nombres B ser A::X. Al cambiar la directiva de uso con una declaración de uso (using C::X), entonces se resuelve en C::X como se esperaba.

La norma dice sobre el uso de directivas [7.3.4.2]:

A usando directiva especifica que los nombres en el espacio de nombres nominados se pueden utilizar en el ámbito en el que aparece el uso de directiva después de que el uso de -directiva. Durante la búsqueda de nombres no calificados (3.4.1), los nombres aparecen como si estuvieran declarados en el espacio de nombres adjunto más cercano que contiene tanto la directiva de uso como el espacio de nombre nominado.

Mi lectura de esto es que C::X debería aparecer como si se declara dentro del espacio de nombres B, ocultando efectivamente A::X. ¿Qué sección (es) del estándar están detrás de esta incoherencia entre el uso de directivas y el uso de declaraciones? ¿Hay alguna forma de ocultar un nombre de un ámbito externo mediante una directiva de uso?

+5

Tal vez la clave esté en * los nombres aparecen como si hubieran sido declarados en el espacio de nombres adjunto más cercano que contiene ** both ** la directiva de uso y el espacio de nombres nominado *. ¿No sería eso '::'? Y si es así, 'A :: X' no se encontraría primero (la búsqueda va desde el espacio de nombres interno) ... aunque no estoy seguro, pero g ++ también capta' A :: X', por lo que es * muy * coherente en todos los compiladores. –

+0

@David Rodríguez - dribeas: Ah, eso lo explicaría ... –

Respuesta

6

El capítulo sobre directiva using parece ser de alguna manera claro que usted está viendo el comportamiento esperado:

7.3.4p2 A usando directiva especifica que los nombres en el espacio de nombres nominados se pueden utilizar en el ámbito en el que aparece la directiva de uso después de la directiva de uso. Durante la búsqueda de nombres no calificados (3.4.1), los nombres aparecen como si hubieran sido declarados en el espacio de nombres adjunto más cercano que contiene ambos using-directive y el espacio de nombres nominado.

7.3.4p3 Una directiva using no agrega ningún miembro a la región declarativa en la que aparece.

Es decir, el utilizando directiva suma los miembros del espacio de nombres para el conjunto de las operaciones de búsqueda de los antepasados ​​espacio de nombres comunes de la Directiva y el espacio de nombres utilizado, no directamente al ámbito en que la utilizando directiva es usado. Esto se establece explícitamente en la segunda cita: no agrega ningún miembro a la región declarativa de using-directive.

Más adelante hay un ejemplo que está destinado a ilustrar algo más, pero en realidad no muestra esto:

7.3.4p4 [...] En otro ejemplo

namespace A { 
    int i; 
} 
namespace B { 
    int i; 
    int j; 
    namespace C { 
    namespace D { 
     using namespace A; 
     int j; 
     int k; 
     int a = i; // B::i hides A::i 
    } 

Ese último ejemplo se usa para aclarar la transitividad (y contiene más código), pero en realidad es equivalente a su código una vez que elimina el código adicional.

Por lo tanto, parece que, en su caso, el uso de directiva no se esconde, sino que se oculta.

+0

Entonces, para mi segunda pregunta, supongo que ** es ** posible ocultar nombres mediante el uso de directivas, pero solo si están en un ámbito externo de el ancestro común del espacio de nombres. –

+0

Yo diría que sí. En cualquier caso, evitaría * usar-directivas * por completo, y solo usar * declaraciones-de-uso * raramente. La búsqueda simplemente se vuelve mucho más complicada y es más difícil determinar qué se está usando exactamente, dónde se define ... Si su necesidad es aplanar el uso de espacios de nombres anidados complejos, considere * alias de espacio de nombres *. –

+0

Evito _using-directives_ en mi código real, esto es solo un intento de 'encontrar dónde vive una clase' al aprovechar las reglas de búsqueda de nombres. –

Cuestiones relacionadas