class C {
using namespace std; // error
};
namespace N {
using namespace std; // ok
}
int main () {
using namespace std; // ok
}
Изменить. Хотите узнать мотивацию.
class C {
using namespace std; // error
};
namespace N {
using namespace std; // ok
}
int main () {
using namespace std; // ok
}
Изменить. Хотите узнать мотивацию.
Я точно не знаю, но я предполагаю, что разрешение этого в области класса может вызвать путаницу:
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.
}
}
Потому что стандарт С++ явно запрещает его. Из С++ 03 §7.3.4 [namespace.udir]:
using-directive: using namespace ::optnested-name-specifieroptnamespace-name ;
Директива-указатель не должна отображаться в области видимости класса, но может отображаться в области пространства имен или в области блока. [Примечание: при поиске имени пространства имен в директиве using рассматриваются только имена пространства имен, см. 3.4.6. ]
Почему стандарт С++ запрещает это? Я не знаю, спросите члена комитета ISO, который утвердил языковой стандарт.
Я считаю, что логика состоит в том, что это, вероятно, будет путать. В настоящее время при обработке идентификатора уровня класса поиск сначала будет искать в области класса, а затем в охватывающем пространстве имен. Разрешение using namespace
на уровне класса будет иметь некоторые побочные эффекты, связанные с тем, как выполняется поиск. В частности, это нужно было бы выполнить где-то между проверкой этой конкретной области класса и проверкой охватывающего пространства имен. То есть: 1) объединить уровень уровня и использовать поиск уровня пространства имен, 2) искать используемое пространство имен после области класса, но перед любой другой областью класса, 3) искать используемое пространство имен прямо перед охватывающим пространством имен. 4) поиск объединен с охватывающим пространством имен.
.
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
на уровне пространства имен. Это не добавит к этому никакого нового значения, но, с другой стороны, усложнит поиск для разработчиков компилятора. Поиск идентификатора пространства имен теперь не зависит от того, где в коде запускается поиск. Когда внутри класса, если lookup не находит идентификатор в области класса, он будет возвращаться к поиску пространства имен, но это точно такой же поиск пространства имен, который используется в определении функции, нет необходимости поддерживать новое состояние. Когда объявление using
найдено на уровне пространства имен, содержимое используемого пространства имен помещается в это пространство имен для всех запросов, связанных с пространством имен. Если на уровне класса было разрешено using namespace
, для поиска пространства имен в одном и том же пространстве имен были бы разные результаты, в зависимости от того, откуда был вызван поиск, и это сделает реализацию поиска более сложной без какого-либо дополнительного значения.Во всяком случае, моя рекомендация не использовать декларацию using namespace
вообще. Это упрощает анализ кода без необходимости хранить содержимое всех пространств имен.
Но зачем вам это нужно? Просто поместите класс в отдельный файл и укажите пространства имен, которые вы хотите, в случае, если вы не хотите, чтобы другие классы достигли их.