Primero, algo de terminología:
- declaración de uso :
using std::vector;
- directiva-de-uso :
using namespace std;
Creo que el uso de directivas de uso está bien, siempre que no se utilicen en el ámbito global en un archivo de encabezado. Así que teniendo
using namespace std;
en su archivo .cpp no es realmente un problema, y si resulta serlo, está completamente bajo su control (e incluso puede tener un alcance en bloques particulares si lo desea). No veo ninguna razón en particular para saturar el código con una gran cantidad de std::
calificadores, simplemente se convierte en un montón de ruido visual. Sin embargo, si no está usando un montón de nombres del std
espacio de nombres en su código, tampoco veo ningún problema en omitir la directiva. Es una tautología: si la directiva no es necesaria, no es necesario utilizarla.
De manera similar, si puede arreglárselas con algunas declaraciones de uso (en lugar de directivas de uso ) para tipos específicos en el std
espacio de nombres, entonces no hay razón por la que no deba traer solo esos nombres específicos al espacio de nombres actual. De la misma manera, creo que sería una locura y una molestia contable tener 25 o 30 declaraciones de uso cuando una sola directiva de uso funcionaría igual de bien.
También es bueno tener en cuenta que hay ocasiones en las que debe usar una declaración using. Consulte el "Elemento 25: Considere la posibilidad de admitir un intercambio sin lanzamiento" de Scott Meyers de Effective C ++, tercera edición. Para que una función genérica con plantilla use el 'mejor' método de intercambio para un tipo parametrizado, debe hacer uso de una declaración de uso y una búsqueda dependiente de argumentos (también conocida como búsqueda de ADL o Koenig):
template< typename T >
void foo( T& x, T& y)
{
using std::swap; // makes std::swap available in this function
// do stuff...
swap( x, y); // will use a T-specific swap() if it exists,
// otherwise will use std::swap<T>()
// ...
}
Creo que deberíamos mirar los modismos comunes para varios idiomas que hacen un uso significativo de los espacios de nombres. Por ejemplo, Java y C # usan espacios de nombres en gran medida (posiblemente más que C ++). La forma más común en que los nombres dentro de los espacios de nombres se usan en esos lenguajes es llevándolos al alcance actual en masa con el equivalente de una directiva using. Esto no causa problemas generalizados, y las pocas veces que se trata de un problema se maneja en forma de "excepción" tratando con los nombres en cuestión a través de nombres completamente calificados o mediante alias, como se puede hacer en C ++.
Herb Sutter y Andrei Alexandrescu tienen esto que decir en "Ítem 59: No escriba usos de espacios de nombres en un archivo de encabezado o antes de un #include" de su libro, Estándares de codificación C ++: 101 reglas, pautas y mejores prácticas:
En resumen: puede y debe usar el espacio de nombres usando declaraciones y directivas libremente en sus archivos de implementación después #include
directivas y sentirse bien al respecto. A pesar de las repetidas afirmaciones en sentido contrario, los espacios de nombres que utilizan declaraciones y directivas no son malos y no frustran el propósito de los espacios de nombres. Más bien, son los que hacen que los espacios de nombres sean utilizables.
Stroupstrup a menudo se cita diciendo, "No contaminen el espacio de nombres global", en "El lenguaje de programación C ++, tercera edición". De hecho dice eso (C.14 [15]), pero se refiere al capítulo C.10.1 donde dice:
Una declaración de uso agrega un nombre a un ámbito local. Una directiva de uso no lo hace; simplemente hace que los nombres sean accesibles en el ámbito en el que fueron declarados. Por ejemplo:
namespaceX {
int i , j , k ;
}
int k ;
void f1()
{
int i = 0 ;
using namespaceX ; // make names from X accessible
i++; // local i
j++; // X::j
k++; // error: X::k or global k ?
::k ++; // the global k
X::k ++; // X’s k
}
void f2()
{
int i = 0 ;
using X::i ; // error: i declared twice in f2()
using X::j ;
using X::k ; // hides global k
i++;
j++; // X::j
k++; // X::k
}
Un nombre declarado localmente (declarado por una declaración ordinaria o por una declaración de uso) oculta declaraciones no locales del mismo nombre, y cualquier sobrecarga ilegal del nombre se detecta en el punto de declaración.
Tenga en cuenta el error de ambigüedad para k++
en
f1()
. Los nombres globales no tienen preferencia sobre los nombres de los espacios de nombres accesibles en el ámbito global. Esto proporciona una protección significativa contra conflictos de nombres accidentales y, lo que es más importante, garantiza que no se obtengan ventajas al contaminar el espacio de nombres global.
Cuando las bibliotecas que declaran muchos nombres se hacen accesibles a través de directivas de uso, es una ventaja significativa que los conflictos de nombres no utilizados no se consideren errores.
...
Espero ver una disminución radical en el uso de nombres globales en nuevos programas que utilizan espacios de nombres en comparación con los programas tradicionales de C y C ++. Las reglas para los espacios de nombres se diseñaron específicamente para no ofrecer ventajas a un usuario "perezoso" de nombres globales sobre alguien que se cuida de no contaminar el alcance global.
¿Y cómo se tiene la misma ventaja que un 'usuario perezoso de nombres globales'? Aprovechando la directiva using, que hace que los nombres de un espacio de nombres estén disponibles para el ámbito actual de forma segura .
Tenga en cuenta que hay una distinción: los nombres en el std
espacio de nombres puestos a disposición de un ámbito con el uso adecuado de una directiva de uso (colocando la directiva después de #includes
) no contaminan el espacio de nombres global. Es simplemente hacer que esos nombres estén disponibles fácilmente y con una protección continua contra los enfrentamientos.