¿Cuál es el alcance de la declaración "using" en C ++?

100

Estoy usando la declaración 'using' en C ++ para agregar std :: string y std :: vector al espacio de nombres local (para evitar escribir innecesarios 'std ::' s).

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 de 'uso' en cada archivo cpp que incluya el encabezado?

Jeff Lake
fuente
18
En caso de que no quede claro en las otras respuestas aquí: - ¡No coloque una usingdeclaración (o usingdirectiva) en el alcance del archivo en un archivo / encabezado de inclusión! Eso causará dolores de cabeza a los usuarios del encabezado.
Michael Burr
De hecho, no ponga una usingdeclaración ( directiva a fortiori ) en un encabezado en absoluto , ¡ incluso dentro de un espacio de nombres! Consulte el alcance de la declaración de uso dentro de un espacio de nombres para conocer los problemas que esto causa.
Nils von Barth
@NilsvonBarth: Eso es un poco simplificado. El uso usingen el alcance de la función y la clase es seguro con respecto al problema discutido.
Sebastian Mach
Quizás le interese leer sobre la función de búsqueda de ADL C ++ .
Alexis Wilke

Respuestas:

59

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

Jeremy Ruten
fuente
51
... que es generalmente algo malo.
Catskul
17
Pero si coloca la usingdeclaración dentro de un namespace, está limitada al alcance de ese espacio de nombres, por lo que generalmente está bien (con las advertencias habituales sobre sus necesidades y estilo particulares).
Cero
1
... pero si coloca el uso dentro de un espacio de nombres, asegúrese de no hacerlo para tratar de evitar algo que normalmente es una mala idea, como si no pudiera encerrar 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 hemos usado namespace :: resolvers en primer lugar. Si es un problema tan grande al escribir, ya sea una macro (que puede llevar fácilmente a olores de código) o mejor aún, aíslelo en su propia fuente .cpp, donde solo usará el espacio de nombres allí.
osirisgothra
1
Si bien esta y otras respuestas similares son buenos consejos, no responden a la pregunta.
Emile Cormier
116

No hay nada especial en los archivos de encabezado que impida la usingdeclaración. Es una simple sustitución de texto antes de que comience la compilación.

Puede limitar una usingdeclaración a un ámbito:

void myFunction()
{
   using namespace std; // only applies to the function's scope
   vector<int> myVector;
}
Eclipse
fuente
12
¡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 usingdentro de una función (¡o incluso una mejor TESTmacro!) Hace que mi vida sea mucho mejor.
dwanderson
54

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

  • Colocado en la parte superior de un archivo, tiene alcance en todo ese archivo.
  • Si se trata de un archivo de encabezado, tendrá alcance en todos los archivos que incluyan ese encabezado. En general, esta " no es una buena idea ", ya que puede tener efectos secundarios inesperados.
  • De lo contrario, la instrucción using tiene alcance dentro del bloque que la contiene desde el punto en que ocurre hasta el 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.
dagorym
fuente
5
Pensé que no era posible agregar una usingdeclaración dentro del alcance de la clase ... Tenía la misma pregunta que el OP por eso, ya que quería evitar escribir por std::todas partes. Obtuve clases que usan muchos vectores con punteros inteligentes y el std::prefijo de cinco caracteres agrega mucha longitud de línea, lo que me parece que se lee peor. Entonces, me preguntaba si una usingdirectiva dentro del espacio de nombres que contiene la clase estaba bien. (Incluso si está dentro de un encabezado.)
thomthom
5
¿Qué pasa si se coloca dentro del alcance de un namespace { ... }?
einpoklum
Entonces puede escribir totalmente: {usando el espacio de nombres blabla; clase bla {}; } y que el uso se aplicará solo a la clase?
Dinaiz
8

El alcance es cualquier alcance en el que se encuentre la declaración de uso.

Si este es un alcance global, entonces será de alcance 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 .

JohnMcG
fuente
3
Eso no es lo suficientemente fuerte. Reemplazar evitar con Don't
Martin York
1
Pero evitar es más fuerte que no hacerlo. "Evite golpear a los otros autos"
bobobobo
6

En el caso citado, el archivo ("unidad de traducción"), lo que significa que sí, todos los archivos que lo incluyen.

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

Generalmente, si necesita especificar un espacio de nombres en un encabezado, a menudo es mejor calificar completamente cada identificador necesario.

James Curran
fuente
Tenga en cuenta que la usingdeclaración en una clase no se comporta de la misma manera que fuera de una clase; por ejemplo, no puede usarla en coutlugar de std::couten el ámbito de la clase.
Cero
2

Eso es correcto. El alcance es el módulo que usa la usingdeclaración. Si algún archivo de encabezado que incluye un módulo tiene usingdeclaraciones, el alcance de esas declaraciones será ese módulo, así como cualquier otro módulo que incluya los mismos encabezados.

Ates Goral
fuente
1

Hay algunos comentarios que son bastante incondicionales cuando dicen "No". Eso es demasiado severo, pero tienes que entender cuándo está bien.

Escribir using std::stringnunca está bien. Escribir using ImplementationDetail::Fooen 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;
}
MSalters
fuente
1
El usuario del encabezado puede entonces escribirMyNS::Foo
Peter Remmers
Un mejor ejemplo es using boost::posix_time::ptime. Seguro que el usuario podría escribir, MyNS::ptimepero ese no es el fin del mundo, y podría verse compensado por la conveniencia de poder tener funciones como MyFunction(ptime a, ptime b).
Cero
5
¿Por quéusing std::string nunca está bien? ¿Incluso en su propio espacio de nombres para guardar muchos std::prefijos?
thomthom
@thomthom está bien cuando se incluye en un ámbito como su propio espacio de nombres.
jcoffland