class C {
using namespace std; // error
};
namespace N {
using namespace std; // ok
}
int main () {
using namespace std; // ok
}
Editar : quiero saber la motivación detrás de esto.
c++
namespaces
using
language-lawyer
iammilind
fuente
fuente
using namespace
. C # permite algo similar, pero solo en el ámbito del archivo. C ++ leusing namespace
permite incorporar un espacio de nombres en otro.class/struct
. Simplemente no está permitido. Pero la respuesta aceptada discute un razonamiento muy lógico para rechazarlo. es decir, dónde considerarHello::World
y dónde considerarWorld
. Espero que despeje la duda.Respuestas:
No lo sé exactamente, pero supongo que permitir esto en el ámbito de la clase podría causar confusión:
namespace Hello { typedef int World; } class Blah { using namespace Hello; public: World DoSomething(); } //Should this be just World or Hello::World ? World Blah::DoSomething() { //Is the using namespace valid in here? }
Dado que no hay una forma obvia de hacer esto, el estándar simplemente dice que no se puede.
Ahora, la razón por la que esto es menos confuso cuando hablamos de ámbitos de espacio de nombres:
namespace Hello { typedef int World; } namespace Other { using namespace Hello; World DoSomething(); } //We are outside of any namespace, so we have to fully qualify everything. Therefore either of these are correct: //Hello was imported into Other, so everything that was in Hello is also in Other. Therefore this is okay: Other::World Other::DoSomething() { //We're outside of a namespace; obviously the using namespace doesn't apply here. //EDIT: Apparently I was wrong about that... see comments. } //The original type was Hello::World, so this is okay too. Hello::World Other::DoSomething() { //Ditto } namespace Other { //namespace Hello has been imported into Other, and we are inside Other, so therefore we never need to qualify anything from Hello. //Therefore this is unambiguiously right World DoSomething() { //We're inside the namespace, obviously the using namespace does apply here. } }
fuente
using namespace Hello;
dentro de otronamespace
también (y declarando laextern
función dentro de él).Hello::World Blah::DoSomething()
oBlah::World Blah::DoSomething()
(si se permitió), el tipo de retorno de una definición de función miembro no se considera que esté en el alcance de la clase en el lenguaje, por lo que debe estar calificado. Considere el ejemplo válido de reemplazar el alcance de la clase porusing
untypedef Hello::World World;
at. Así que no debería haber sorpresas allí.Porque el estándar C ++ lo prohíbe explícitamente. De C ++ 03 §7.3.4 [namespace.udir]:
¿Por qué lo prohíbe el estándar C ++? No sé, pregúntele a un miembro del comité ISO que aprobó el estándar de lenguaje.
fuente
Creo que la razón es que probablemente sería confuso. Actualmente, mientras se procesa un identificador de nivel de clase, la búsqueda buscará primero en el ámbito de la clase y luego en el espacio de nombres adjunto. Permitir el
using namespace
nivel a nivel de clase tendría algunos efectos secundarios sobre cómo se realiza ahora la búsqueda. En particular, tendría que realizarse en algún momento entre la verificación de ese ámbito de clase particular y la verificación del espacio de nombres adjunto. Es decir: 1) fusionar el nivel de clase y las búsquedas de nivel de espacio de nombres usado, 2) buscar el espacio de nombre usado después del alcance de clase pero antes de cualquier otro alcance de clase, 3) buscar el espacio de nombre usado justo antes del espacio de nombre adjunto. 4) la búsqueda se fusionó con el espacio de nombres adjunto..
namespace A { void foo() {} struct B { struct foo {}; void f() { foo(); // value initialize a A::B::foo object (current behavior) } }; } struct C { using namespace A; struct foo {}; void f() { foo(); // call A::foo } };
.
namespace A { void foo() {} } void bar() {} struct base { void foo(); void bar(); }; struct test : base { using namespace A; void f() { foo(); // A::foo() bar(); // base::bar() } };
.
namespace A { void foo( int ) { std::cout << "int"; } } void foo( double ) { std::cout << "double"; } struct test { using namespace A; void f() { foo( 5.0 ); // would print "int" if A is checked *before* the // enclosing namespace } };
using
declaración en el nivel del espacio de nombres. No agregaría ningún valor nuevo a eso, pero por otro lado complicará la búsqueda de los implementadores del compilador. La búsqueda de identificadores de espacio de nombres ahora es independiente de en qué parte del código se desencadena la búsqueda. Cuando dentro de una clase, si la búsqueda no encuentra el identificador en el ámbito de la clase, recurrirá a la búsqueda de espacio de nombres, pero esa es exactamente la misma búsqueda de espacio de nombres que se usa en una definición de función, no es necesario mantener un nuevo estado. Cuando lausing
declaración se encuentra a nivel de espacio de nombres, el contenido del espacio de nombres usado se lleva a ese espacio de nombres para todas las búsquedas que involucran el espacio de nombres. Siusing namespace
se permitió a nivel de clase, habría diferentes resultados para la búsqueda de espacio de nombres del mismo espacio de nombres exacto dependiendo de dónde se desencadenó la búsqueda, y eso haría que la implementación de la búsqueda sea mucho más compleja sin valor adicional.De todos modos, mi recomendación es no emplear la
using namespace
declaración en absoluto. Hace que el código sea más fácil de razonar sin tener que tener en cuenta el contenido de todos los espacios de nombres.fuente
using
existe. Declarando cosas a propósito en espacios de nombres largos anidados profundos. Por ejemplo,glm
hace eso y usa múltiples trucos para activar / presentar características cuando el cliente usausing
.using namespace std::placeholders
. cf en.cppreference.com/w/cpp/utility/functional/bindnamespace ph = std::placeholders;
Esto probablemente no esté permitido debido a la apertura frente a la cercanía.
La importación de espacios de nombres en clases conduciría a casos divertidos como este:
namespace Foo {} struct Bar { using namespace Foo; }; namespace Foo { using Baz = int; // I've just extended `Bar` with a type alias! void baz(); // I've just extended `Bar` with what looks like a static function! // etc. }
fuente
namespace Foo
al orden de búsqueda para todo el código dentro de la definición de tipo destruct Bar
, muy parecido a poner esa línea en cada cuerpo de función miembro en línea, excepto que también estaría activa para inicializadores de llaves o iguales, etc. expiran en la llave de cierre, lo mismo queusing namespace
dentro de un cuerpo de función miembro. Ahora, desafortunadamente, no parece haber ninguna forma de usar la búsqueda Koenig-with-fallback en un inicializador de llaves o iguales sin contaminar el espacio de nombres adjunto.Creo que es un defecto del idioma. Puede utilizar la solución alternativa a continuación. Teniendo en cuenta esta solución alternativa, es fácil sugerir reglas de resolución de conflictos de nombres para el caso en que se cambie el idioma.
namespace Hello { typedef int World; } // surround the class (where we want to use namespace Hello) // by auxiliary namespace (but don't use anonymous namespaces in h-files) namespace Blah_namesp { using namespace Hello; class Blah { public: World DoSomething1(); World DoSomething2(); World DoSomething3(); }; World Blah::DoSomething1() { } } // namespace Blah_namesp // "extract" class from auxiliary namespace using Blah_namesp::Blah; Hello::World Blah::DoSomething2() { } auto Blah::DoSomething3() -> World { }
fuente