IT

인라인 네임 스페이스 란 무엇입니까?

lottoking 2020. 3. 8. 16:24
반응형

인라인 네임 스페이스 란 무엇입니까?


C ++ 11은 inline namespaces를 허용 하며, 모든 멤버도 자동으로 둘러싸고 namespace있습니다. 나는 이것의 유용한 적용을 생각할 수 없다-누군가 inline namespace가 필요한 상황 과 가장 관용적 인 해결책이 있는 상황에 대한 간략하고 간결한 예를 줄 수 있습니까?

(A는 때 발생 또한, 나에게 분명하지 않다 namespace선언 된 inline다른 파일에 살고있는 수있는 모든 선언을, 하나가 아니라.이 문제를 구걸 아닌가요?)


인라인 네임 스페이스는 심볼 버전 관리 와 유사한 라이브러리 버전 관리 기능 이지만 특정 바이너리 실행 형식 (예 : 플랫폼 별)의 기능이 아닌 C ++ 11 수준 (예 : 크로스 플랫폼)에서 순수하게 구현됩니다.

라이브러리 작성자는 중첩 네임 스페이스를 모든 선언이 주변 네임 스페이스에있는 것처럼 보이게하고 작동 할 수있는 메커니즘입니다 (인라인 네임 스페이스를 중첩 할 수 있으므로 "더 중첩 된"이름은 첫 번째가 아닌 이름까지 퍼집니다) -인라인 네임 스페이스를 사용하고 선언이 그 사이의 네임 스페이스에있는 것처럼 보이고 작동합니다).

예를 들어의 STL 구현을 고려하십시오 vector. C ++의 시작부터 인라인 네임 스페이스가 있다면 C ++ 98에서 헤더 <vector>는 다음과 같을 것입니다.

namespace std {

#if __cplusplus < 1997L // pre-standard C++
    inline
#endif

    namespace pre_cxx_1997 {
        template <class T> __vector_impl; // implementation class
        template <class T> // e.g. w/o allocator argument
        class vector : __vector_impl<T> { // private inheritance
            // ...
        };
    }
#if __cplusplus >= 1997L // C++98/03 or later
                         // (ifdef'ed out b/c it probably uses new language
                         // features that a pre-C++98 compiler would choke on)
#  if __cplusplus == 1997L // C++98/03
    inline
#  endif

    namespace cxx_1997 {

        // std::vector now has an allocator argument
        template <class T, class Alloc=std::allocator<T> >
        class vector : pre_cxx_1997::__vector_impl<T> { // the old impl is still good
            // ...
        };

        // and vector<bool> is special:
        template <class Alloc=std::allocator<bool> >
        class vector<bool> {
            // ...
        };

    };

#endif // C++98/03 or later

} // namespace std

의 값에 따라 __cplusplus하나 또는 다른 vector구현이 선택됩니다. 코드베이스가 C ++ 98 이전 버전으로 작성되었고 vector컴파일러를 업그레이드 할 때 C ++ 98 버전으로 인해 문제가 발생하는 경우 "모두"는 참조를 찾는 것 std::vector입니다. 코드베이스와로 대체하십시오 std::pre_cxx_1997::vector.

을위한 새로운 공간 도입, 다음 기본으로 제공하고, STL 공급 업체는 절차를 다시 반복 std::vectoremplace_back(++ 11 C 필요)를 지원하고 하나 IFF를 인라인 __cplusplus == 201103L.

그렇다면 왜 새로운 언어 기능이 필요합니까? 나는 이미 같은 효과를 내기 위해 다음을 할 수 있습니까?

namespace std {

    namespace pre_cxx_1997 {
        // ...
    }
#if __cplusplus < 1997L // pre-standard C++
    using namespace pre_cxx_1997;
#endif

#if __cplusplus >= 1997L // C++98/03 or later
                         // (ifdef'ed out b/c it probably uses new language
                         // features that a pre-C++98 compiler would choke on)

    namespace cxx_1997 {
        // ...
    };
#  if __cplusplus == 1997L // C++98/03
    using namespace cxx_1997;
#  endif

#endif // C++98/03 or later

} // namespace std

의 가치에 따라 __cplusplus구현 중 하나를 얻습니다.

그리고 당신은 거의 정확할 것입니다.

다음과 같은 유효한 C ++ 98 사용자 코드를 고려하십시오 ( std이미 C ++ 98의 네임 스페이스 있는 템플릿을 완전히 특수화 할 수 있음).

// I don't trust my STL vendor to do this optimisation, so force these 
// specializations myself:
namespace std {
    template <>
    class vector<MyType> : my_special_vector<MyType> {
        // ...
    };
    template <>
    class vector<MyOtherType> : my_special_vector<MyOtherType> {
        // ...
    };
    // ...etc...
} // namespace std

이것은 사용자가 STL에서 찾은 것보다 더 효율적인 구현을 알 수있는 유형 집합에 대한 자체 벡터 구현을 제공하는 완벽하게 유효한 코드입니다.

그러나 : 템플릿을 전문화 할 때는 vector선언 된 네임 스페이스 std에서 그렇게해야 합니다. 표준 에서는 네임 스페이스에 선언되어 있으므로 사용자가 형식을 특수화 할 것으로 기대합니다.

이 코드는 버전이없는 네임 스페이스 std또는 C ++ 11 인라인 네임 스페이스 기능과 함께 작동하지만 사용 된 버전 관리 트릭과 는 작동하지 않습니다 . using namespace <nested>이는 vector정의 된 실제 네임 스페이스가 std직접적 이지 않은 구현 세부 사항을 노출시키기 때문입니다 .

중첩 된 네임 스페이스를 감지 할 수있는 다른 구멍이 있지만 (아래 주석 참조) 인라인 네임 스페이스는 모두 연결합니다. 그리고 그게 전부입니다. 미래에는 엄청나게 유용하지만 표준 AFAIK는 자체 표준 라이브러리에 대해 인라인 네임 스페이스 이름을 지정하지 않으므로 (이 경우 잘못된 것으로 입증되고 싶습니다) 타사 라이브러리에만 사용할 수 있습니다. 표준 자체 (컴파일러 벤더가 이름 지정 체계에 동의하지 않는 한).


http://www.stroustrup.com/C++11FAQ.html#inline-namespace(Bjarne Stroustrup이 작성하고 유지 관리하는 문서로 대부분의 C ++ 11 기능에 대한 대부분의 동기를 알고 있어야한다고 생각합니다. )

이에 따르면, 이전 버전과의 호환성을 위해 버전 관리를 허용하는 것입니다. 여러 개의 내부 네임 스페이스를 정의하고 가장 최근 네임 스페이스를 만듭니다 inline. 어쨌든, 버전 관리에 관심이없는 사람들을위한 기본 설정입니다. 가장 최신 버전이 아직 기본이 아닌 미래 또는 최신 버전 일 수 있다고 생각합니다.

주어진 예는 다음과 같습니다.

// file V99.h:
inline namespace V99 {
    void f(int);    // does something better than the V98 version
    void f(double); // new feature
    // ...
}

// file V98.h:
namespace V98 {
    void f(int);    // does something
    // ...
}

// file Mine.h:
namespace Mine {
#include "V99.h"
#include "V98.h"
}

#include "Mine.h"
using namespace Mine;
// ...
V98::f(1);  // old version
V99::f(1);  // new version
f(1);       // default version

나는 왜 당신이 using namespace V99;namespace에 넣지 않았는지 즉시 알지 Mine못하지만,위원회의 동기 부여에 대한 Bjarne의 말을 취하기 위해 유스 케이스를 완전히 이해할 필요는 없습니다.


위의 모든 답변 외에도.

인라인 네임 스페이스를 사용하여 ABI 정보 또는 기호의 함수 버전을 인코딩 할 수 있습니다. 이러한 이유로 인해 이전 ABI 호환성을 제공하는 데 사용됩니다. 인라인 네임 스페이스를 사용하면 링커 심볼 이름에만 영향을 미치므로 API를 변경하지 않고도 정보를 맹 글링 된 이름 (ABI)에 삽입 할 수 있습니다.

이 예제를 고려하십시오.

Foo객체에 대한 참조를 가져 bar오고 아무것도 반환하지 않는 함수를 작성한다고 가정하십시오 .

main.cpp에서 말해

struct bar;
void Foo(bar& ref);

이 파일을 객체로 컴파일 한 후이 파일의 심볼 이름을 확인하면

$ nm main.o
T__ Z1fooRK6bar 

링커 심볼 이름은 다를 수 있지만 함수 이름과 인수 유형을 어딘가에 인코딩해야합니다.

이제 bar다음과 같이 정의 될 수 있습니다 .

struct bar{
   int x;
#ifndef NDEBUG
   int y;
#endif
};

빌드 유형에 따라 bar동일한 링커 기호가있는 두 가지 유형 / 레이아웃을 참조 할 수 있습니다.

이러한 동작을 방지하기 위해 bar빌드 유형에 따라 링커 기호 bar가 다른 인라인 네임 스페이스로 구조체 래핑합니다 .

따라서 다음과 같이 작성할 수 있습니다.

#ifndef NDEBUG
inline namespace rel { 
#else
inline namespace dbg {
#endif
struct bar{
   int x;
#ifndef NDEBUG
   int y;
#endif
};
}

이제 각 객체의 객체 파일을 보면 릴리스를 사용하고 디버그 플래그를 사용하여 하나를 작성합니다. 링커 심볼에는 인라인 네임 스페이스 이름도 포함되어 있습니다. 이 경우

$ nm rel.o
T__ ZROKfoo9relEbar
$ nm dbg.o
T__ ZROKfoo9dbgEbar

링커 심볼 이름이 다를 수 있습니다.

기호 이름이 존재 rel하고 있음 dbg을 확인하십시오.

이제 디버그를 릴리스 모드로 또는 그 반대로 링크하려고하면 런타임 오류와 반대로 링커 오류가 발생합니다.


실제로 인라인 네임 스페이스에 대한 또 다른 용도를 발견했습니다.

Qt는 , 당신은 몇 가지 여분을 얻을, 좋은 사용하여 기능을 Q_ENUM_NS다시 바깥 쪽 네임 스페이스를 선언하는 Meta Object를 가지고 있어야한다, Q_NAMESPACE. 그러나 Q_ENUM_NS작동 Q_NAMESPACE 하려면 동일한 파일 ⁽¹⁾에 해당 파일이 있어야합니다. 그리고 하나만 있거나 중복 정의 오류가 발생합니다. 이것은 사실상 모든 열거가 동일한 헤더에 있어야 함을 의미합니다. 왝.

또는 ... 인라인 네임 스페이스를 사용할 수 있습니다. 에 열거를 숨기면inline namespace메타 개체가 다른 맹 글링 된 이름을 가지지 만 추가 네임 스페이스와 같은 사용자를 찾는 것은 존재하지 않습니다.

따라서 어떤 이유로 든 필요한 경우 하나의 네임 스페이스처럼 보이는 여러 개의 하위 네임 스페이스로 항목을 분할하는 데 유용합니다 . 물론 이것은 using namespace inner외부 네임 스페이스 에 쓰는 것과 비슷 하지만 내부 네임 스페이스의 이름을 두 번 쓰는 DRY 위반이 없습니다 .


  1. 실제로 그것보다 더 나쁩니다. 동일한 중괄호 세트에 있어야합니다.

  2. 메타 객체를 정규화하지 않고 메타 객체에 액세스하려고하지 않는 한 메타 객체는 거의 직접 사용되지 않습니다.

참고 URL : https://stackoverflow.com/questions/11016220/what-are-inline-namespaces-for



반응형