Почему "использование пространства имен X;"не допускается на уровне класса/структуры?



class C {
using namespace std; // error
};
namespace N {
using namespace std; // ok
}
int main () {
using namespace std; // ok
}


редактировать: хочу знать мотивацию за ним.

1361   4  

4 ответов:

Я точно не знаю, но я предполагаю, что разрешение этого в области класса может вызвать путаницу:

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?
}

поскольку нет очевидного способа сделать это, стандарт просто говорит, что вы не можете.

теперь причина, по которой это менее запутанно, когда мы говорим о пространствах имен:

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.
    }
}

потому что стандарт C++ запрещает это. Из C++03 §7.3.4 [пространство имен.udir]:

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

A using-directive не должен отображаться в области класса, но может отображаться в области пространства имен или в области блока. [Примечание: при поиске имени пространства имен в директиве using учитываются только имена пространств имен, см. 3.4.6. ]

почему стандарт C++ запрещает? Я не знаю, спросите члена комитета ИСО, который одобрил стандарт языка.

Я считаю, что обоснование заключается в том, что это, вероятно, будет запутанным. В настоящее время при обработке идентификатора уровня класса lookup сначала выполняет поиск в области класса, а затем во вложенном пространстве имен. Позволяя using namespace на уровне класса будет иметь довольно некоторые побочные эффекты на то, как теперь выполняется поиск. В частности, это должно было бы выполняться когда-то между проверкой этой конкретной области класса и проверкой заключающего пространства имен. То есть: 1) объединить уровень класса и поиск на уровне используемого пространства имен, 2) Поиск используемого пространства имен после область класса, но перед любой другой областью класса, 3)Поиск используемого пространства имен прямо перед заключительным пространством имен. 4) поиск объединен с окружающим пространством имен.

  1. это будет иметь большое значение, где идентификатор на уровне класса будет тени любой код в пространство имен, но это не тени 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
   }
};
  1. поиск сразу после этой области класса. Это будет иметь странный эффект затенения членов базовых классов. Текущий поиск не смешивает поиск на уровне класса и пространства имен, и при выполнении поиска класса он будет проходить весь путь до базовых классов до С учетом пространства имен. Поведение было бы удивительно в том, что оно не рассматривало бы пространство имен на аналогичном уровне с окружающим пространством имен. Опять же,используется пространство имен будет иметь приоритет над окружающим пространством имен.

.

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. поиск прямо перед включающим пространством имен. Проблема с этим подходом заключается в том, что было бы удивительно для многих. Учтите, что пространство имен определяется в другой единице перевода, так что следующий код не может быть виден сразу:

.

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. слияние с окружающим пространством имен. Это будет иметь тот же самый эффект, что и применение using декларации на уровне пространства имен. Это не добавит к этому никакого нового значения, но, с другой стороны, усложнит поиск для разработчиков компилятора. Поиск идентификатора пространства имен, теперь зависит от того, где в коде поиска срабатывает. Когда внутри класса, если lookup не находит идентификатор в области класса, он вернется к поиску пространства имен, но это точно такой же поиск пространства имен, который используется в определении функции, нет необходимости поддерживать новое состояние. Когда using декларация находится на уровне пространства имен, содержание используется пространства имен принес в это пространство имен для все поиск с использованием пространства имен. Если using namespace было разрешено в на уровне класса будут разные результаты для поиска пространства имен одного и того же пространства имен в зависимости от того, откуда был инициирован поиск, и это сделает реализацию поиска намного более сложной без дополнительного значения.

в любом случае, моя рекомендация -не использовать using namespace декларации. Это делает код проще рассуждать, не имея в виду содержимое всех пространств имен.

но зачем вам это нужно? Просто поместите класс в отдельный файл и включите пространства имен, которые вы хотите, если вы не хотите, чтобы другие классы достигали их.

Comments

    Ничего не найдено.