"네임 스페이스 X 사용"이유 클래스 / 구조체 수준 내에서 허용되지 않습니까?


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

편집 : 동기를 알고 싶어요.


1
@pst : C #에는 using namespace. C #은 비슷한 것을 허용하지만 파일 범위에서만 가능합니다. C ++를 using namespace사용하면 하나의 네임 스페이스를 다른 네임 스페이스에 통합 할 수 있습니다.
Billy ONeal 2011-06-13

2
이 질문과 중복 됩니까?
greatwolf

@ZachSaw, 귀하의 우려를 이해합니다. 관련성에 따라 Qn을 닫으려고했습니다. 이 게시물에는 표준에 대한 더 객관적인 답변과 참조가 포함되어 있으므로 열어 두었습니다. 과거에 내 오래된 Qn의 대부분은 새로운 Qn에 의해 폐쇄되었습니다. 이 결정이 적절하지 않다고 생각되면 다이아몬드 모드에 신고하십시오. 유감 없음. :-)
iammilind

@iammilind는 TBH를 덜 신경 쓸 수 없습니다. 요즘은 엉망입니다. 그러나 "정확히 모르겠습니다"로 시작하는 게시물을 표시하는 것은 실제로 "표준에 대한보다 객관적인 답변 및 참조"를 포함합니다. ㅋ.
Zach Saw

@ZachSaw, 나는 받아 들여진 대답뿐만 아니라 전체 게시물에 대해 이야기하고있었습니다. 예, 객관적이지만 표준 견적 이이 답변에 포함되어 있습니다. 표준에서도 "using namespace"가 내부에서 허용되지 않는 이유가 정당화되지 않기 때문에 "모름"으로 시작합니다 class/struct. 단순히 허용되지 않습니다. 그러나 받아 들여지는 대답은 그것을 허용하지 않는 매우 논리적 인 근거를 논의합니다. 즉, 고려할 Hello::World위치와 고려할 위치 World. 의심을 해소하는 희망.
iammilind

답변:


36

정확히 모르겠지만 클래스 범위에서 이것을 허용하면 혼란이 발생할 수 있습니다.

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

5
+1, 나는이 이유를 생각했지만 using namespace Hello;다른 내부 에도 동일한 것이 적용됩니다 namespace(및 extern내부 함수 선언 ).
iammilind

10
나는 그것이 혼란스럽지 않다고 생각한다. C ++는 추측에 관한 것이 아닙니다. 허용된다면 C ++ ISO위원회는 언어 사양에 명시했을 것입니다. 그렇다면 혼란스럽지 않을 것입니다. 그렇지 않으면 이것이 혼란 스러울 수도 있습니다. ideone.com/npOeD ... 그런 코딩에 대한 규칙은 사양에 지정되어 있습니다.
Nawaz

1
@Nawaz : 대부분의 언어 사용자입니다. 나는 C ++가 추측에 관한 것이라고 말한 적이 없습니다. 사양이 설계 될 때 대부분의 프로그래머가 미리 예상하는 동작으로 설계되었다고 말하고 있습니다. 그리고 종이의 규칙은 종종 있습니다 표준 시도가 모호 할 것이 아니라 항상 성공하지 않습니다 - 혼란.
빌리 ONeal

6
첫 번째 예에서는 다음과 같아야합니다. Hello::World Blah::DoSomething()또는 Blah::World Blah::DoSomething()(허용 된 경우) 멤버 함수 정의의 반환 유형이 언어의 클래스 범위에있는 것으로 간주되지 않으므로 정규화되어야합니다. 을 대체하는 유효한 예를 고려 using로모그래퍼 typedef Hello::World World;클래스 범위에있다. 따라서 거기에는 놀라운 일이 없어야합니다.
데이비드 로드리게스는 - dribeas

2
허용된다면 어휘 범위 수준에서 적용될 것이라고 생각합니다. 나는 이것이 사실상 놀라움이없는 "명백한"해결책이라고 생각합니다.
Thomas Eding 2011

19

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위원회 위원에게 물어보십시오.


46
기술적으로 정확하지만 쓸모없는 또 다른 대답; 최악의 종류. 1)위원회보다 더 많은 사람들이 답을 알고 있습니다. 2) 위원들이 SO에 참여 3) 답을 모르는 경우 (질문의 정신을 감안할 때) 왜 답이됩니까?
Catskul

5
@Catskul : 쓸모없는 대답이 아닙니다. 표준이 이것을 명시 적으로 다루고 금지한다는 것을 아는 것은 매우 유용합니다. 가장 많이 찬성 된 답변이 "정확히 모릅니다"로 시작한다는 것도 아이러니합니다. 또한 "표준 금지"는 "컴파일러가 허용하지 않기 때문에 허용되지 않음"과 동일하지 않습니다. 후자의 경우 다음과 같은 후속 질문에 대답하지 않기 때문입니다. 내 컴파일러에 문제가 있습니까? 컴파일러가 표준을 준수하지 않습니까? 내가 알지 못하는 다른 것들의 부작용입니까? 등
antonone

9

나는 그것이 아마도 혼란 스러울 것이라는 근거가 있다고 생각합니다. 현재 클래스 수준 식별자를 처리하는 동안 조회는 먼저 클래스 범위에서 검색 한 다음 둘러싸는 네임 스페이스에서 검색합니다. using namespaceat 클래스 수준을 허용하면 조회가 수행되는 방식에 상당한 부작용이있을 것입니다. 특히, 특정 클래스 범위를 확인하고 둘러싸는 네임 스페이스를 확인하는 사이에 언젠가 수행되어야합니다. 즉, 1) 클래스 수준과 사용 된 네임 스페이스 수준 조회를 병합하고, 2) 클래스 범위 뒤에서 다른 클래스 범위보다 먼저 사용 된 네임 스페이스를 조회하고, 3) 둘러싸는 네임 스페이스 바로 앞에서 사용 된 네임 스페이스를 조회합니다. 4) 둘러싸는 네임 스페이스와 병합 된 조회.

  1. 이 클래스 수준의 식별자는 것이 큰 차이를 만들 것 그림자 를 둘러싸는 네임 스페이스의 모든 식별자를하지만,하지 않을 그림자 사용하는 네임 스페이스를. 다른 네임 스페이스의 클래스와 동일한 네임 스페이스에서 사용 된 네임 스페이스에 대한 액세스 가 다를 수 있다는 점에서 효과는 이상 할 것입니다.

.

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네임 스페이스 수준에서 선언 을 적용하는 것과 똑같은 효과를 갖습니다 . 여기에 새로운 값을 추가하지는 않지만 다른 한편으로는 컴파일러 구현 자 검색을 복잡하게 만듭니다. 네임 스페이스 식별자 조회는 이제 코드에서 조회가 트리거되는 위치와 독립적입니다. 클래스 내부에서 조회가 클래스 범위에서 식별자를 찾지 못하면 네임 스페이스 조회로 대체되지만 함수 정의에 사용 된 것과 정확히 동일한 네임 스페이스 조회이므로 새 상태를 유지할 필요가 없습니다. 때 using선언 네임 스페이스 수준에서 발견,의 내용 사용되는 네임 스페이스된다 가져온 에 해당 네임 스페이스에 모든 네임 스페이스를 포함하는 조회. 만약using namespace 클래스 수준에서 허용 된 경우 조회가 트리거 된 위치에 따라 정확히 동일한 네임 스페이스의 네임 스페이스 조회에 대해 다른 결과가있을 수 있으며 추가 값없이 조회 구현이 훨씬 더 복잡해집니다.

어쨌든, 선언문을 전혀 사용 하지 않는 것이 좋습니다 using namespace. 모든 네임 스페이스의 내용을 염두에 두지 않고도 코드를 추론하기가 더 간단 해집니다.


1
나는 사용이 암묵적인 기이함을 만드는 경향이 있다는 데 동의합니다. 그러나 일부 라이브러리는 using존재 하는 사실을 중심으로 설계 될 수 있습니다. 깊숙이 중첩 된 긴 네임 스페이스에서 의도적으로 선언합니다. 예를 들어 glm클라이언트가 .NET을 사용할 때 여러 트릭을 사용하여 기능을 활성화 / 표시합니다 using.
v.oddou

STL에서도 마찬가지 using namespace std::placeholders입니다. cf en.cppreference.com/w/cpp/utility/functional/bind
v.oddou

@ v.oddou는 :namespace ph = std::placeholders;
데이비드 로드리게스는 - dribeas

1

이것은 아마도 개방성폐쇄성 때문에 허용되지 않을 것입니다.

  • C ++의 클래스와 구조체는 항상 닫힌 엔터티입니다. 정확히 한 곳에서 정의됩니다 (선언과 구현을 분할 할 수 있음).
  • 네임 스페이스는 임의로 열고, 다시 열고, 확장 할 수 있습니다.

네임 스페이스를 클래스로 가져 오면 다음과 같은 재미있는 경우가 발생합니다.

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 조회를 사용할 수있는 방법이없는 것 같습니다.
Ben Voigt

0

언어의 결함이라고 생각합니다. 아래 해결 방법을 사용할 수 있습니다. 이 해결 방법을 염두에두면 언어가 변경 될 경우 이름 충돌 해결 규칙을 쉽게 제안 할 수 있습니다.

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

설명을 추가해 주시겠습니까?
Kishan Bharda

예, 약간의 코멘트를 추가
naprimeroleg
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.