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.
}
}
using namespace Hello;
다른 내부 에도 동일한 것이 적용됩니다 namespace
(및 extern
내부 함수 선언 ).
Hello::World Blah::DoSomething()
또는 Blah::World Blah::DoSomething()
(허용 된 경우) 멤버 함수 정의의 반환 유형이 언어의 클래스 범위에있는 것으로 간주되지 않으므로 정규화되어야합니다. 을 대체하는 유효한 예를 고려 using
로모그래퍼 typedef Hello::World World;
클래스 범위에있다. 따라서 거기에는 놀라운 일이 없어야합니다.
C ++ 표준이이를 명시 적으로 금지하기 때문입니다. C ++ 03 §7.3.4 [namespace.udir]에서 :
지시어 사용 : using namespace :: opt nested-name-specifier opt namespace-name ;
사용-지시어는 클래스 범위에 나타나지 않습니다,하지만 네임 스페이스 범위 또는 블록 범위에 나타날 수 있습니다. [참고 : using-directive에서 namespace-name을 검색 할 때 네임 스페이스 이름 만 고려됩니다. 3.4.6을 참조하십시오. ]
C ++ 표준이이를 금지하는 이유는 무엇입니까? 모르겠습니다. 언어 표준을 승인 한 ISO위원회 위원에게 물어보십시오.
나는 그것이 아마도 혼란 스러울 것이라는 근거가 있다고 생각합니다. 현재 클래스 수준 식별자를 처리하는 동안 조회는 먼저 클래스 범위에서 검색 한 다음 둘러싸는 네임 스페이스에서 검색합니다. using namespace
at 클래스 수준을 허용하면 조회가 수행되는 방식에 상당한 부작용이있을 것입니다. 특히, 특정 클래스 범위를 확인하고 둘러싸는 네임 스페이스를 확인하는 사이에 언젠가 수행되어야합니다. 즉, 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
네임 스페이스 수준에서 선언 을 적용하는 것과 똑같은 효과를 갖습니다 . 여기에 새로운 값을 추가하지는 않지만 다른 한편으로는 컴파일러 구현 자 검색을 복잡하게 만듭니다. 네임 스페이스 식별자 조회는 이제 코드에서 조회가 트리거되는 위치와 독립적입니다. 클래스 내부에서 조회가 클래스 범위에서 식별자를 찾지 못하면 네임 스페이스 조회로 대체되지만 함수 정의에 사용 된 것과 정확히 동일한 네임 스페이스 조회이므로 새 상태를 유지할 필요가 없습니다. 때 using
선언 네임 스페이스 수준에서 발견,의 내용 사용되는 네임 스페이스된다 가져온 에 해당 네임 스페이스에 모든 네임 스페이스를 포함하는 조회. 만약using namespace
클래스 수준에서 허용 된 경우 조회가 트리거 된 위치에 따라 정확히 동일한 네임 스페이스의 네임 스페이스 조회에 대해 다른 결과가있을 수 있으며 추가 값없이 조회 구현이 훨씬 더 복잡해집니다.어쨌든, 선언문을 전혀 사용 하지 않는 것이 좋습니다 using namespace
. 모든 네임 스페이스의 내용을 염두에 두지 않고도 코드를 추론하기가 더 간단 해집니다.
using
존재 하는 사실을 중심으로 설계 될 수 있습니다. 깊숙이 중첩 된 긴 네임 스페이스에서 의도적으로 선언합니다. 예를 들어 glm
클라이언트가 .NET을 사용할 때 여러 트릭을 사용하여 기능을 활성화 / 표시합니다 using
.
using namespace std::placeholders
입니다. cf en.cppreference.com/w/cpp/utility/functional/bind
namespace ph = std::placeholders;
이것은 아마도 개방성 과 폐쇄성 때문에 허용되지 않을 것입니다.
네임 스페이스를 클래스로 가져 오면 다음과 같은 재미있는 경우가 발생합니다.
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.
}
namespace Foo
유형 정의 내의 모든 코드에 대한 검색 순서 에이 구문을 추가 합니다 struct Bar
.하지만 여전히 using namespace
멤버 함수 본문 내부 와 동일하게 닫는 중괄호에서 만료됩니다 . 이제 안타깝게도 둘러싸고있는 네임 스페이스를 오염시키지 않고 중괄호 또는 같음 이니셜 라이저에서 Koenig-with-fallback 조회를 사용할 수있는 방법이없는 것 같습니다.
언어의 결함이라고 생각합니다. 아래 해결 방법을 사용할 수 있습니다. 이 해결 방법을 염두에두면 언어가 변경 될 경우 이름 충돌 해결 규칙을 쉽게 제안 할 수 있습니다.
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
{
}
using namespace
. C #은 비슷한 것을 허용하지만 파일 범위에서만 가능합니다. C ++를using namespace
사용하면 하나의 네임 스페이스를 다른 네임 스페이스에 통합 할 수 있습니다.