¿Por qué no se permite "usar espacio de nombres X;" dentro del nivel de clase / estructura?


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.

Author: iammilind, 2011-06-13

4 answers

No lo sé exactamente, pero mi conjetura es que permitir esto en el ámbito de 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 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.
    }
}
 27
Author: Billy ONeal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-13 19:11:15

Porque el estándar de C++ lo prohíbe explícitamente. De C++03 §7.3.4 [espacio de nombres.udir]:

using-directive:
    using namespace ::optnested-name-specifieroptnamespace-name ;

A using-directive no aparecerá en el ámbito de clase, pero puede aparecer en el ámbito de espacio de nombres o en el ámbito de bloque. [Nota: al buscar un namespace-name en una directiva using, solo se consideran nombres de espacios de nombres (véase 3.4.6). ]

¿Por qué el estándar C++ lo prohíbe? No lo sé, pregúntale a un miembro del comité de ISO que aprobó el estándar de lenguaje.

 22
Author: Adam Rosenfield,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-13 05:05:48

Creo que la razón es que probablemente sería confuso. Actualmente, mientras se procesa un identificador de nivel de clase, lookup buscará primero en el ámbito de clase y luego en el espacio de nombres adjunto. Permitir el using namespace a nivel de clase tendría bastantes efectos secundarios sobre cómo se realiza la búsqueda ahora. En particular, tendría que realizarse en algún momento entre la comprobación de ese ámbito de clase en particular y la comprobación del espacio de nombres que encierra. Es decir: 1) combinar el nivel de clase y utilizado búsquedas a nivel de espacio de nombres, 2) buscar el espacio de nombres usado después de el ámbito de clase pero antes de cualquier otro ámbito de clase, 3) buscar el espacio de nombres usado justo antes del espacio de nombres que lo encierra. 4) búsqueda combinada con el espacio de nombres adjunto.

  1. Esto haría una gran diferencia, donde un identificador a nivel de clase sombrearía cualquier identificador en el espacio de nombres adjunto, pero no sombrearía un usado espacio de nombres. El efecto sería extraño, en ese acceso para el usado espacio de nombres de una clase en un espacio de nombres diferente y desde el mismo espacio de nombres sería diferente:

.

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
   }
};
  1. Buscar 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 a nivel de clase y espacio de nombres, y al realizar la búsqueda de clases irá hasta las clases base antes de considerando el espacio de nombres que encierra. El comportamiento sería sorprendente en el sentido de que no consideraría el espacio de nombres en un nivel similar al espacio de nombres que lo encierra. De nuevo, el espacio de nombres usado se priorizaría sobre el espacio de nombres que lo encierra.

.

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()
   }
};
  1. Buscar justo antes del espacio de nombres que encierra. El problema con este enfoque es una vez más que sería sorprendente para muchos. Tenga en cuenta que el espacio de nombres está definido en una unidad de traducción diferente, por lo que el siguiente código no se puede ver en 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
   }
};
  1. Fusionar con el espacio de nombres que contiene. Esto tendría exactamente el mismo efecto que aplicar la declaración using a nivel de espacio de nombres. No añadiría ningún valor nuevo a eso, pero por otro lado complicaría la búsqueda de implementadores de compiladores. La búsqueda de identificador de espacio de nombres ahora es independiente del lugar del código en el que se activa la búsqueda. Cuando está dentro de una clase, si lookup no encuentra el identificador en el ámbito de la clase, volverá a búsqueda de espacio de nombres, pero es exactamente la misma búsqueda de espacio de nombres que se usa en una definición de función, no hay necesidad de mantener un nuevo estado. Cuando la declaración using se encuentra a nivel de espacio de nombres, el contenido del espacio de nombres usado es traído a ese espacio de nombres para todas las búsquedas que involucran el espacio de nombres. Si using namespace se permitía 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 realizó la búsqueda desencadenado desde, y que haría que la implementación de la búsqueda mucho más compleja para ningún valor adicional.

De todos modos, mi recomendación es no emplear la declaración using namespace 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.

 8
Author: David Rodríguez - dribeas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-13 08:01:01

Pero ¿para qué lo necesitas? Simplemente coloque la clase en el archivo separado e incluya los espacios de nombres que desee en caso de que no desee que otras clases lleguen a ellos.

 -3
Author: Sergey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-13 05:03:33