수색…


소개

여러 라이브러리를 사용할 때 이름 충돌을 방지하는 데 사용되며 네임 스페이스는 함수, 클래스, 유형 등에 대한 선언적 접두사입니다.

통사론

  • 네임 스페이스 식별자 ( opt ) { 선언 -seq }
  • 인라인 네임 스페이스 식별자 ( opt ) { 선언 -seq } / * 이후 C ++ 11 * /
  • 인라인 ( opt ) 네임 스페이스 속성 지정자 - seq 식별자 ( opt ) { 선언 - seq } / * 이후 C ++ 17 * /
  • namespace enclosing-namespace-specifier :: identifier { 선언 - seq } / * 이후 C ++ 17 * /
  • 네임 스페이스 식별자 = 정규화 된 네임 스페이스 지정자 ;
  • using namespace 네스트 - 네임 지정자 ( opt ) 네임 스페이스 - 이름 ;
  • namepace 네스트 - 네임 지정자 ( opt ) 네임 스페이스 - 네임을 사용하는 attribute-specifier-seq ; / * C ++ 11 이후 * /

비고

키워드 namespace 는 문맥에 따라 세 가지 다른 의미를 지닙니다.

  1. 선택적인 이름과 중괄호로 묶인 선언 순서가 뒤따를 때 , 새로운 선언 은 네임 스페이스를 정의 하거나 기존 네임 스페이스확장합니다 . 이름이 생략되면 이름 공간은 이름이 없는 이름 공간 입니다.

  2. 이름과 등호가 따라 오면 네임 스페이스 별칭을 선언합니다.

  3. 네임 스페이스 이름을 using 하고 그 뒤에 오는 경우 using 지시문 을 사용하여 주어진 네임 스페이스의 이름을 정규화되지 않은 이름 조회에서 찾을 수 있습니다 (그러나 현재 범위에서 해당 이름을 다시 선언하지는 않습니다). using 지시문 은 클래스 범위에서 발생할 수 없습니다.

using namespace std; 낙담합니다. 왜? namespace std 가 거대하기 때문에! 이는 이름 충돌이 발생할 가능성이 높음을 의미합니다.

//Really bad!
using namespace std;

//Calculates p^e and outputs it to std::cout
void pow(double p, double e) { /*...*/ }

//Calls pow
pow(5.0, 2.0); //Error! There is already a pow function in namespace std with the same signature,
               //so the call is ambiguous

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

C ++ 네임 스페이스는 네임 스페이스의 이름 앞에 접두어가 붙은 C ++ 엔터티 (함수, 클래스, 변수)의 컬렉션입니다. 네임 스페이스 내에 코드를 작성할 때, 네임 스페이스에 속한 네임 엔티티는 네임 스페이스 이름의 접두어가 될 필요는 없지만 그 바깥에있는 엔티티는 완전한 이름을 사용해야합니다. 정규화 된 이름의 형식은 <namespace>::<entity> 입니다. 예:

namespace Example
{
  const int test = 5;

  const int test2 = test + 12; //Works within `Example` namespace
}

const int test3 = test + 3; //Fails; `test` not found outside of namespace.

const int test3 = Example::test + 3; //Works; fully qualified name used.

네임 스페이스는 관련 정의를 함께 그룹화하는 데 유용합니다. 쇼핑몰을 비유하십시오. 일반적으로 쇼핑몰은 여러 상점으로 나뉘며 각 상점은 특정 카테고리의 품목을 판매합니다. 한 상점은 전자 제품을 판매하고 다른 상점은 신발을 판매 할 수 있습니다. 상점 유형의 이러한 논리적 구분은 구매자가 찾고있는 항목을 찾는데 도움이됩니다. 네임 스페이스는 구매자와 같은 c ++ 프로그래머가 논리 방식으로 구성하여 원하는 기능, 클래스 및 변수를 찾는 데 도움이됩니다. 예:

namespace Electronics
{
    int TotalStock;
    class Headphones
    {
        // Description of a Headphone (color, brand, model number, etc.)
    };
    class Television
    {
        // Description of a Television (color, brand, model number, etc.)
    };
}

namespace Shoes
{
    int TotalStock;
    class Sandal
    {
        // Description of a Sandal (color, brand, model number, etc.)
    };
    class Slipper
    {
        // Description of a Slipper (color, brand, model number, etc.)
    };
}

하나의 네임 스페이스가 미리 정의되어 있습니다.이 네임 스페이스는 이름이 없지만 :: 로 표시 할 수있는 전역 네임 스페이스입니다. 예:

void bar() {
    // defined in global namespace
}
namespace foo {
    void bar() {
        // defined in namespace foo
    }
    void barbar() {
        bar();   // calls foo::bar()
        ::bar(); // calls bar() defined in global namespace
    }
}

네임 스페이스 만들기

네임 스페이스를 만드는 것은 정말 쉽습니다.

//Creates namespace foo
namespace Foo
{
    //Declares function bar in namespace foo
    void bar() {}
}

bar 를 호출하려면 네임 스페이스를 먼저 지정한 다음 범위 분석 연산자 인 :: :를 지정해야합니다.

Foo::bar();

하나의 네임 스페이스를 다른 네임 스페이스에 만들 수 있습니다 (예 :

namespace A
{
    namespace B
    {
        namespace C
        {
            void bar() {}
        }
    }
}
C ++ 17

위의 코드는 다음과 같이 단순화 될 수 있습니다.

namespace A::B::C
{
    void bar() {}
}

네임 스페이스 확장하기

namespace 의 유용한 기능은 확장 할 수 있다는 것입니다 (멤버를 추가 할 수 있음).

namespace Foo
{
    void bar() {}
}

//some other stuff

namespace Foo
{
    void bar2() {}
}

지시어 사용하기

'using' 이라는 키워드에는 세 가지 맛이 있습니다. 키워드 '네임 스페이스'와 결합하면 'using directive'라고 쓸 수 있습니다.

Foo:: 네임 스페이스의 모든 항목 앞에 Foo:: 를 쓰지 않으려면 네임 스페이스 Foo 를 사용 using namespace Foo; Foo 모든 것을 가져올 수 있습니다.

namespace Foo
{
    void bar() {}
    void baz() {}
}

//Have to use Foo::bar()
Foo::bar();

//Import Foo
using namespace Foo;
bar(); //OK
baz(); //OK

전체 네임 스페이스가 아닌 네임 스페이스에서 선택된 엔티티를 가져올 수도 있습니다.

using Foo::bar;
bar(); //OK, was specifically imported
baz(); // Not OK, was not imported

주의 사항 : 헤더 파일에서 using namespace 하는 것은 대부분의 경우 나쁜 스타일로 간주됩니다. 이 작업이 완료되면 헤더가 포함 된 모든 파일에서 네임 스페이스를 가져옵니다. 네임 스페이스 using " using 하지 않는"방법이 없으므로 네임 스페이스 오염 (전역 네임 스페이스에서 더 많은 또는 예기치 않은 기호)이 발생할 수 있습니다. 문제의 설명은 다음 예제를 참조하십시오.

/***** foo.h *****/
namespace Foo
{
    class C;
}

/***** bar.h *****/
namespace Bar
{
    class C;
}

/***** baz.h *****/
#include "foo.h"
using namespace Foo;

/***** main.cpp *****/
#include "bar.h"
#include "baz.h"

using namespace Bar;
C c; // error: Ambiguity between Bar::C and Foo::C

using 지시문 은 클래스 범위에서 발생할 수 없습니다.

인수 종속 조회

명시 적 네임 스페이스 한정자없이 함수를 호출 할 때 컴파일러는 해당 함수의 매개 변수 유형 중 하나가 해당 네임 스페이스에도있는 경우 네임 스페이스 내의 함수를 호출하도록 선택할 수 있습니다. 이를 "인수 종속 조회 (Argument Dependent Lookup)"또는 ADL :

namespace Test
{
  int call(int i);

  class SomeClass {...};

  int call_too(const SomeClass &data);
}

call(5); //Fails. Not a qualified function name.

Test::SomeClass data;

call_too(data); //Succeeds

Test 네임 스페이스의 매개 변수 유형이 없으므로 call 이 실패합니다. SomeClassTest 의 멤버이므로 call_too 작동하므로 ADL 규칙을 사용할 수 있습니다.

언제 ADL이 발생하지 않습니까?

정규화되지 않은 조회가 클래스 멤버, 블록 범위에서 선언 된 함수 또는 함수 유형이 아닌 함수를 찾으면 ADL은 발생하지 않습니다. 예 :

void foo();
namespace N {
    struct X {};
    void foo(X ) { std::cout << '1'; }
    void qux(X ) { std::cout << '2'; }
}

struct C {
    void foo() {}
    void bar() {
        foo(N::X{}); // error: ADL is disabled and C::foo() takes no arguments
    }
};

void bar() {
    extern void foo(); // redeclares ::foo
    foo(N::X{});       // error: ADL is disabled and ::foo() doesn't take any arguments
}

int qux;

void baz() {
    qux(N::X{}); // error: variable declaration disables ADL for "qux"
}

인라인 네임 스페이스

C ++ 11

inline namespace 는 인 클로즈 된 네임 스페이스에 인라인 네임 스페이스의 내용을 포함하므로

namespace Outer
{
    inline namespace Inner
    {
        void foo();
    }
}

대체로

namespace Outer
{

    namespace Inner
    {
        void foo();
    }

    using Inner::foo;
}

하지만 요소에서 Outer::Inner:: 및에 연관된 Outer:: 동일하다.

그래서 다음은 동급입니다.

Outer::foo();
Outer::Inner::foo();

using namespace Inner; 하는 대안 using namespace Inner; 템플릿 특수화와 같이 까다로운 부분에 대해서는 동등하지 않습니다.

에 대한

#include <outer.h> // See below

class MyCustomType;
namespace Outer
{
    template <>
    void foo<MyCustomType>() { std::cout << "Specialization"; }
}
  • 인라인 네임 스페이스는 Outer::foo 의 특수화를 허용합니다.

    // outer.h
    // include guard omitted for simplification
    
    namespace Outer
    {
        inline namespace Inner
        {
            template <typename T>
            void foo() { std::cout << "Generic"; }
        }
    }
    
  • using namespace 사용하면 Outer::foo 의 특수화가 허용되지 않습니다.

    // outer.h
    // include guard omitted for simplification
    
    namespace Outer
    {
        namespace Inner
        {
            template <typename T>
            void foo() { std::cout << "Generic"; }
        }
        using namespace Inner;
        // Specialization of `Outer::foo` is not possible
        // it should be `Outer::Inner::foo`.
    }
    

인라인 네임 스페이스는 여러 버전을 inline 하고 기본값으로 허용하는 방법입니다.

namespace MyNamespace
{
    // Inline the last version
    inline namespace Version2
    {
        void foo(); // New version
        void bar();
    }

    namespace Version1 // The old one
    {
        void foo();
    }

}

그리고 사용법

MyNamespace::Version1::foo(); // old version
MyNamespace::Version2::foo(); // new version
MyNamespace::foo();           // default version : MyNamespace::Version1::foo();

이름없는 / 익명의 네임 스페이스

이름없는 네임 스페이스는 이름에 내부 연결이 있는지 확인하는 데 사용할 수 있습니다 (현재 번역 단위에서만 참조 할 수 있음). 이러한 네임 스페이스는 다른 네임 스페이스와 같은 방식으로 정의되지만 이름은 없습니다.

namespace {
    int foo = 42;
}

foo 는 나타나는 번역 단위에서만 볼 수 있습니다.

헤더 파일에 이름없는 네임 스페이스를 사용하지 않는 것이 좋습니다. 이렇게하면 포함 된 모든 번역 단위에 대한 콘텐츠 버전이 제공됩니다. 이것은 const가 아닌 전역을 정의 할 때 특히 중요합니다.

// foo.h
namespace {
    std::string globalString;
}

// 1.cpp
#include "foo.h" //< Generates unnamed_namespace{1.cpp}::globalString ...

globalString = "Initialize";

// 2.cpp
#include "foo.h" //< Generates unnamed_namespace{2.cpp}::globalString ...

std::cout << globalString; //< Will always print the empty string

조밀 한 중첩 네임 스페이스

C ++ 17
namespace a {
  namespace b {
    template<class T>
    struct qualifies : std::false_type {};
  }
}

namespace other {
  struct bob {};
}

namespace a::b {
  template<>
  struct qualifies<::other::bob> : std::true_type {};
}

한 단계에서 ab 네임 스페이스를 모두 입력 할 수 있습니다. namespace a::b 는 C ++ 17에서 시작합니다.

긴 네임 스페이스 앨리어싱

이것은 일반적으로 라이브러리의 구성 요소를 참조하는 긴 네임 스페이스 참조의 이름을 바꾸거나 줄이기 위해 사용됩니다.

namespace boost
{
    namespace multiprecision
    {
        class Number ...
    }
}

namespace Name1 = boost::multiprecision;


//    Both Type declarations are equivalent
boost::multiprecision::Number X   //    Writing the full namespace path, longer
Name1::Number Y                   //    using the name alias, shorter

별칭 선언 범위

별칭 선언은 선행 사용 문에 의해 영향을받습니다.

namespace boost
{
    namespace multiprecision
    {
        class Number ...
    }
}


using namespace boost;

//   Both Namespace are equivalent 
namespace Name1 = boost::multiprecision;
namespace Name2 = multiprecision;

그러나 다음과 같은 경우에 네임 스페이스에 어떤 이름 공간이 있는지 혼동하는 것이 더 쉽습니다.

namespace boost
{
    namespace multiprecision
    {
        class Number ...
    }
}

namespace numeric
{
    namespace multiprecision
    {
        class Number ...
    }
}

using namespace numeric;
using namespace boost;

//    Not recommended as 
//    its not explicitly clear whether Name1 refers to
//    numeric::multiprecision or boost::multiprecision
namespace Name1 = multiprecision;

//    For clarity, its recommended to use absolute paths
//    instead
namespace Name2 = numeric::multiprecision;
namespace Name3 = boost::multiprecision;

네임 스페이스 별칭

네임 스페이스는 namespace 식별자 = 구문을 사용하여 별칭 ( 즉, 동일한 네임 스페이스의 다른 이름)을 부여 할 수 있습니다. 별칭 이름 공간의 멤버는 별칭 이름으로 한정하여 액세스 할 수 있습니다. 다음 예에서 중첩 된 네임 스페이스 AReallyLongName::AnotherReallyLongName 은 입력하기가 불편하므로 함수 qux 로컬로 별칭 N 선언합니다. 네임 스페이스의 멤버는 N:: 사용하여 액세스 할 수 있습니다.

namespace AReallyLongName {
    namespace AnotherReallyLongName {
        int foo();
        int bar();
        void baz(int x, int y);
    }
}
void qux() {
    namespace N = AReallyLongName::AnotherReallyLongName;
    N::baz(N::foo(), N::bar());
}


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow