c++ - ¿Por qué "usar namespace X;" no está permitido dentro del nivel de clase/estructura?
namespaces using (4)
class C {
using namespace std; // error
};
namespace N {
using namespace std; // ok
}
int main () {
using namespace std; // ok
}
Edición : Quiero saber la motivación detrás de él.
¿Pero por qué lo necesitas? Simplemente coloque la clase en el archivo separado e incluya los espacios de nombres que desee en caso de que no quiera que otras clases los alcancen.
Creo que la razón es que probablemente sería confuso. Actualmente, mientras se procesa un identificador de nivel de clase, la búsqueda primero buscará en el ámbito de la clase y luego en el espacio de nombres adjunto. Permitir el using namespace
de using namespace
en el nivel de clase tendría algunos efectos secundarios en la forma en que se realiza la búsqueda. En particular, tendría que realizarse en algún momento entre la comprobación de ese ámbito de clase particular y la comprobación del espacio de nombres adjunto. Es decir: 1) fusionar el nivel de clase y las búsquedas de nivel de espacio de nombres utilizadas, 2) buscar el espacio de nombres usado después del alcance de la clase pero antes de cualquier otro alcance de clase, 3) buscar el espacio de nombres usado justo antes del espacio de nombres adjunto. 4) búsqueda combinada con el espacio de nombres adjunto.
- Esto haría una gran diferencia, ya que un identificador en el nivel de clase ocultaría cualquier identificador en el espacio de nombres adjunto, pero no ocultaría un espacio de nombres usado . El efecto sería extraño, ya que el acceso al espacio de nombres usado desde una clase en un espacio de nombres diferente y desde el mismo espacio de nombres diferiría:
.
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
}
};
- Búsqueda justo después de este ámbito de clase. Esto tendría el extraño efecto de seguir a los miembros de las clases base. La búsqueda actual no mezcla las búsquedas de nivel de clase y espacio de nombres, y cuando se realiza la búsqueda de clases irá hasta las clases base antes de considerar el espacio de nombres adjunto. El comportamiento sería sorprendente ya que no consideraría el espacio de nombres en un nivel similar al espacio de nombres adjunto. Nuevamente, el espacio de nombres usado se priorizará sobre el espacio de nombres que lo contiene.
.
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()
}
};
- Busque justo antes del espacio de nombres adjunto. El problema con este enfoque es, de nuevo, que sería sorprendente para muchos. Tenga en cuenta que el espacio de nombres está definido en una unidad de traducción diferente, de modo que el siguiente código no se puede ver de una vez:
.
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
}
};
- Combinar con el espacio de nombres adjunto. Esto tendría exactamente el mismo efecto que la aplicación de la declaración de
using
en el nivel de espacio de nombres. No agregaría ningún valor nuevo a eso, pero por otro lado complicará la búsqueda para los implementadores del compilador. La búsqueda del identificador de espacio de nombres ahora es independiente de donde en el código se activa la búsqueda. Cuando se encuentra dentro de una clase, si la búsqueda no encuentra el identificador en el ámbito de la clase, volverá a la búsqueda de espacio de nombres, pero es exactamente la misma búsqueda de espacio de nombres que se usa en la definición de una función, no hay necesidad de mantener un nuevo estado. Cuando la declaración deusing
se encuentra en el nivel del espacio de nombres, el contenido del espacio de nombres utilizado se lleva a ese espacio de nombres para todas las búsquedas que involucran el espacio de nombres. Si se permitierausing namespace
a nivel de clase, habría resultados diferentes para la búsqueda del espacio de nombres exactamente del mismo espacio de nombres dependiendo de dónde se activó la búsqueda, y eso haría que la implementación de la búsqueda fuera mucho más compleja sin ningún valor adicional.
De todos modos, mi recomendación es no emplear la declaración de using namespace
. 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.
No 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?
}
Como no hay una forma obvia de hacerlo, el estándar simplemente dice que no se puede.
Ahora, la razón es menos confusa cuando estamos hablando 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.
}
}
Porque el estándar C ++ lo prohíbe explícitamente. De C ++ 03 §7.3.4 [namespace.udir]:
using-directive: using namespace ::opt nested-name-specifieropt namespace-name ;
Una directiva de uso no aparecerá en el ámbito de la clase, pero puede aparecer en el ámbito del espacio de nombres o en el ámbito de bloque. [Nota: al buscar un nombre de espacio de nombres en una directiva de uso, solo se consideran los nombres de los espacios de nombres, ver 3.4.6. ]
¿Por qué el estándar C ++ lo prohíbe? No sé, pregúntele a un miembro del comité de ISO que aprobó el estándar de idioma.