2008-10-21 10 views
80

Estoy usando la declaración 'using' en C++ para agregar std :: string y std :: vector al espacio de nombres local (para guardar tipeo innecesario 'std ::' s).¿Cuál es el alcance de la declaración de "uso" en C++?

using std::string; 
using std::vector; 

class Foo { /*...*/ }; 

¿Cuál es el alcance de esta declaración? Si hago esto en un encabezado, ¿inyectará estas declaraciones 'using' en cada archivo cpp que incluya el encabezado?

+17

Por si acaso no está claro en las otras respuestas aquí: - ** ¡No coloque una declaración 'using' (o' using' directive) en el alcance del archivo en un include file/header! ** Eso lo hará causar dolores de cabeza a los usuarios del encabezado. –

+0

De hecho, no coloque una declaración 'using' (a fortiori * directive *) en un encabezado ** en absoluto **, * ¡incluso dentro de un espacio de nombres! * Consulte [alcance de uso de declaración dentro de un espacio de nombres] (http://stackoverflow.com/q/6175705/2025416) para los problemas que esto ocasiona. –

Respuesta

53

Cuando #incluye un archivo de encabezado en C++, coloca todo el contenido del archivo de encabezado en el lugar donde lo incluyó en el archivo de origen. Por lo tanto, incluir un archivo que tenga una declaración using tiene exactamente el mismo efecto de colocar la declaración using en la parte superior de cada archivo que incluye ese archivo de encabezado.

+43

... que generalmente es algo malo. – Catskul

+13

Pero si coloca la declaración 'using' dentro de un' namespace' está limitado al alcance de ese espacio de nombres, por lo que generalmente está bien (con las advertencias habituales sobre sus necesidades y estilo en particular). – Zero

+1

... pero si lo pones usando dentro de un espacio de nombres, asegúrate de que no lo estás haciendo para tratar de evitar algo que normalmente es una mala idea, como no poder encapsular los métodos de clase declarados fuera del espacio de nombres Y dentro del otro espacio de nombres X, solo para que pueda usar localmente el espacio de nombres X. Es por eso que tenemos uso namespace :: resolvedores en primer lugar. Si es un gran problema de tipeo, ya sea una macro (que puede conducir fácilmente a olores de código) o mejor aún, aíslala en su propia fuente .cpp donde solo usarás el espacio de nombres. – osirisgothra

5

En el caso citado, el archivo ("unidad de traducción"), que significa sí, cada archivo que lo incluye.

También puede poner la instrucción using dentro de la clase, en cuyo caso, está en vigor solo para esa clase.

Generalmente, si necesita especificar un espacio de nombres en un encabezado, a menudo es mejor simplemente calificar completamente todos los identificadores necesarios.

+0

Tenga en cuenta que la declaración 'using' en una clase no se comporta de la misma manera que fuera de una clase; por ejemplo, no puede usarlo, sino' cout' en lugar de 'std :: cout' dentro del alcance de la clase. – Zero

2

Eso es correcto. El alcance es el módulo que usa la declaración using. Si los archivos de encabezado que incluye un módulo tienen declaraciones using, el alcance de esas declaraciones será ese módulo, así como cualquier otro módulo que incluya los mismos encabezados.

86

No hay nada de especial en los archivos de encabezado que mantendrían la declaración using. Es una simple sustitución de texto antes de que comience la compilación.

puede limitar una declaración using a un ámbito:

void myFunction() 
{ 
    using namespace std; // only applies to the function's scope 
    vector<int> myVector; 
} 
+8

¡Nunca pensé que podría usarlo dentro de una función! – Agostino

+1

Tengo un montón de espacios de nombres utilizados por un archivo de tipo "conglomerador", y la prueba unitaria de gmock fue muy tediosa porque cada prueba usaba cosas de un espacio de nombres específico, y pensé que tenía que calificar todas y cada una de las variables . Usar 'using' dentro de una función (¡o incluso una macro de test 'test'!) Hace que mi vida sea mucho mejor. – dwanderson

4

El alcance es lo que el alcance de la declaración using está en

Si este es el alcance global, entonces será en el ámbito global.. Si está en el alcance global de un archivo de encabezado, entonces estará en el alcance global de cada archivo fuente que incluya el encabezado.

Por lo tanto, el consejo general es evitar el uso de declaraciones en el alcance global de los archivos de encabezado.

+2

Eso no es lo suficientemente fuerte. Reemplace Evite con No –

+1

Evitar evitar es más fuerte que no hacerlo. "Evitar golpear a los otros autos" – bobobobo

44

El alcance de la instrucción using depende de dónde se encuentra en el código:

  • colocado en la parte superior de un archivo, que tiene un alcance largo de ese archivo.
  • Si se trata de un archivo de cabecera, tendrá alcance en todos los archivos que incluyan ese encabezado. En general, se trata de "no es una buena idea", ya que puede tener efectos secundarios inesperados
  • De lo contrario la declaración usando tiene alcance dentro del bloque que lo contiene y en el punto en que se produce al final del bloque. Si se coloca dentro de un método, tendrá alcance dentro de ese método. Si se coloca dentro de una definición de clase, tendrá alcance dentro de esa clase.
+4

Pensé que no era posible agregar una instrucción 'using' dentro del alcance de la clase ...? Tuve la misma pregunta que el OP por eso, ya que quería evitar escribir 'std ::' por todas partes. Obtuve clases que usan muchos vectores con punteros inteligentes y el prefijo 'std ::' de cinco caracteres agrega mucha longitud de línea, lo que me parece peor. Entonces, me preguntaba si una directiva 'using' dentro del espacio de nombres que contiene la clase estaba bien. (Incluso si dentro de un encabezado) – thomthom

+0

¿Qué pasa si se coloca dentro del alcance de un 'namespace {...}'? – einpoklum

+0

Así que puedes escribir totalmente: {using namespace blabla; clase blah {}; } y ese uso se aplicará solo a la clase? – Dinaiz

1

Hay algunos comentarios que no están calificados cuando dicen "No hacer".Eso es demasiado severo, pero debes entender cuándo está bien.

Escribir using std::string nunca está bien. Escribiendo using ImplementationDetail::Foo en su propio encabezado, cuando ese encabezado declara ImplementationDetail :: Foo puede estar bien, más aún si la declaración de uso ocurre en su espacio de nombres. P.ej.

namespace MyNS { 
    namespace ImplementationDetail { 
     int Foo; 
    } 
    using ImplementationDetail::Foo; 
} 
+1

El usuario del encabezado puede escribir 'MyNS :: Foo' –

+0

Un mejor ejemplo es' using boost :: posix_time :: ptime'. Seguro que el usuario podría escribir 'MyNS :: ptime', pero ese no es el fin del mundo, y podría compensarse con la conveniencia de poder tener funciones como' MyFunction (ptime a, ptime b) '. – Zero

+4

* ¿Por qué * is 'using std :: string' nunca está bien? ¿Incluso en su propio espacio de nombres para guardar una gran cantidad de prefijos 'std ::'? – thomthom

Cuestiones relacionadas