이름이없는 / 익명 네임 스페이스 대 정적 함수 수 없습니다.

C ++의 기능은 다음과 같이 명명되지 않은 (익명) 네임 스페이스를 만들 수있는 기능입니다.

namespace {
    int cannotAccessOutsideThisFile() { ... }
} // namespace

네임 스페이스의 이름을 지정할 수 없으므로 외부에서 액세스 할 수 없습니다. 그러나 명명되지 않은 네임 스페이스 생성 된 파일 내에서 암시적인 using-clause가있는 것처럼 액세스 할 수 있습니다.

내 질문은 정적 함수를 사용하는 것보다 왜 또는 언제 이것이 좋을까요? 아니면 본질적으로 똑같은 일을하는 두 가지 방법입니까?



답변

C ++ 표준은 섹션 7.3.1.1의 네임 스페이스 네임 스페이스, 단락 2를 읽습니다.


네임 스페이스 범위에서 객체를 선언 할 때는 정적 키워드를 사용하지 않으므로 unnamed-namespace는 탁월한 대안을 제공합니다.

정적은 유형 선언이 아닌 객체, 함수 및 익명 공용체의 이름에만 적용됩니다.

편집하다:

정적 키워드 (번역 단위에서 변수 선언의 가시성에 영향을 미침)를 사용하지 않기로 한 결정이 취소되었습니다 ( ref ). 이 경우 정적 네임 스페이스 나 명명되지 않은 네임 스페이스를 사용하면 본질적으로 정확히 동일한 작업을 수행하는 두 가지 방법으로 돌아갑니다. 자세한 내용은 SO 질문을 참조하십시오 .

이름이없는 네임 스페이스는 여전히 번역 단위 로컬 형식을 정의 할 수있는 이점이 있습니다. 자세한 내용은 SO 질문을 참조하십시오.

크레딧은 Mike Percy 에게이 사실을 알려주었습니다.


답변

익명 네임 스페이스에 메서드를 넣으면 실수로 하나의 정의 규칙을 위반 하지 않으므로 링크 할 수있는 다른 메서드와 동일하게 도우미 메서드의 이름을 지정할 필요가 없습니다.

그리고 luke가 지적한 것처럼 표준에서는 정적 네임 스페이스보다 익명 네임 스페이스를 선호합니다.


답변

static이 놀라운 효과를 갖는 한 가지 경우가 있습니다 (적어도 나에게있었습니다). 14.6.4.2/1의 C ++ 03 표준 상태는 다음과 같습니다.

템플릿 매개 변수에 의존하는 함수 호출의 경우 함수 이름이 규정되지 않은 id 이지만 template-id가 아닌 경우 후보 함수는 다음을 제외하고 일반적인 조회 규칙 (3.4.1, 3.4.2)을 사용하여 찾습니다.

  • 규정되지 않은 이름 조회 (3.4.1)를 사용하는 조회의 경우 템플리트 정의 컨텍스트에서 외부 링크가있는 함수 선언 만 발견됩니다.
  • 연관된 네임 스페이스 (3.4.2)를 사용하는 조회의 경우 템플리트 정의 컨텍스트 또는 템플리트 인스턴스화 컨텍스트에서 외부 링크가있는 함수 선언 만 찾을 수 있습니다.

아래 코드는 예상대로 호출 foo(void*)되지 않습니다 foo(S const &).

template <typename T>
int b1 (T const & t)
{
  foo(t);
}

namespace NS
{
  namespace
  {
    struct S
    {
    public:
      operator void * () const;
    };

    void foo (void*);
    static void foo (S const &);   // Not considered 14.6.4.2(b1)
  }

}

void b2()
{
  NS::S s;
  b1 (s);
}

그 자체로는 그다지 큰 문제는 아니지만 완전히 호환되는 C ++ 컴파일러 (예 : 지원 export하는 static키워드 )의 경우 키워드는 다른 방식으로는 사용할 수없는 기능을 여전히 가지고 있음을 강조합니다 .

// bar.h
export template <typename T>
int b1 (T const & t);

// bar.cc
#include "bar.h"
template <typename T>
int b1 (T const & t)
{
  foo(t);
}

// foo.cc
#include "bar.h"
namespace NS
{
  namespace
  {
    struct S
    {
    };

    void foo (S const & s);  // Will be found by different TU 'bar.cc'
  }
}

void b2()
{
  NS::S s;
  b1 (s);
}

명명되지 않은 네임 스페이스의 함수가 ADL을 사용하는 템플릿에서 찾을 수 없도록하는 유일한 방법은 그것을 만드는 것 static입니다.

Modern C ++ 업데이트

C ++ ’11에서 이름이없는 네임 스페이스의 멤버는 내부적으로 내부적으로 연결되어 있습니다 (3.5 / 4).

명명되지 않은 네임 스페이스 또는 명명되지 않은 네임 스페이스 내에서 직접 또는 간접적으로 선언 된 네임 스페이스에는 내부 연결이 있습니다.

그러나 동시에 14.6.4.2/1은 연결에 대한 언급을 제거하도록 업데이트되었습니다 (C ++ ’14에서 가져옴).

postfix-expression이 종속 이름 인 함수 호출의 경우 후보 함수는 다음을 제외하고 일반적인 조회 규칙 (3.4.1, 3.4.2)을 사용하여 찾습니다.

  • 규정되지 않은 이름 조회 (3.4.1)를 사용하는 조회의 경우 템플리트 정의 컨텍스트의 함수 선언 만 발견됩니다.

  • 연관된 네임 스페이스 (3.4.2)를 사용하는 조회의 경우 템플리트 정의 컨텍스트 또는 템플리트 인스턴스화 컨텍스트에서 찾은 함수 선언 만 발견됩니다.

결과적으로 정적 네임 스페이스 멤버와 이름이없는 네임 스페이스 멤버 간의 이러한 특정 차이점이 더 이상 존재하지 않습니다.


답변

최근에 코드에서 정적 키워드를 익명 네임 스페이스로 교체하기 시작했지만 네임 스페이스의 변수를 더 이상 디버거에서 검사 할 수없는 문제가 발생했습니다. VC60을 사용하고 있었으므로 다른 디버거에서 문제가 아닌지 알 수 없습니다. 내 해결 방법은 ‘모듈’네임 스페이스를 정의하여 cpp 파일의 이름을 지정하는 것입니다.

예를 들어, XmlUtil.cpp 파일에서 XmlUtil_I { ... }모든 모듈 변수 및 함수에 대한 네임 스페이스 를 정의 합니다. 그렇게 XmlUtil_I::하면 디버거에 자격을 적용 하여 변수에 액세스 할 수 있습니다. 이 경우 다른 곳에서 사용하려는 _I공용 네임 스페이스와 구별됩니다 XmlUtil.

익명의 접근 방식과 비교할 때이 접근법의 잠재적 단점은 다른 모듈에서 네임 스페이스 한정자를 사용하여 원하는 정적 범위를 위반 할 수 있다는 것입니다. 그래도 그것이 중요한 관심사인지 모르겠습니다.


답변

C ++ 98 표준에서는 이러한 목적으로 정적 키워드를 사용하지 않습니다. static의 문제는 유형 정의에 적용되지 않는다는 것입니다. 또한 다른 컨텍스트에서 다른 방식으로 사용되는 오버로드 된 키워드이므로 명명되지 않은 네임 스페이스는 일을 조금 단순화합니다.


답변

경험상 필자는 이전에 정적 함수를 익명 네임 스페이스에 넣는 것이 C ++ 방법이지만 이전 컴파일러는 때때로 이것에 문제가있을 수 있습니다. 나는 현재 대상 플랫폼을 위해 몇 개의 컴파일러로 작업하고 있으며 더 현대적인 Linux 컴파일러는 익명 네임 스페이스에 함수를 배치하는 것이 좋습니다.

그러나 지정되지 않은 이후 릴리스까지는 Solaris에서 실행되는 이전 컴파일러가 때때로이를 받아들이고 다른 경우에는 오류로 표시합니다. 이 오류는 그것이 무엇을, 저를 걱정 것이 아니다 수도 그 때 일을 받아 그것을. 따라서 우리가 전반적으로 현대화 될 때까지 익명 네임 스페이스를 선호하는 정적 (보통 클래스 범위) 함수를 계속 사용합니다.


답변

또한이 예제와 같이 변수에 정적 키워드를 사용하는 경우 :

namespace {
   static int flag;
}

매핑 파일에서 볼 수 없습니다