Namespaces
Variants

Qualified name lookup

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

qualified 이름은 범위 지정 연산자 :: 의 오른쪽에 나타나는 이름입니다 (참조: qualified identifiers ). qualified 이름은 다음을 참조할 수 있습니다

  • 클래스 멤버 (정적 및 비정적 함수, 타입, 템플릿 등 포함),
  • 네임스페이스 멤버 (다른 네임스페이스 포함),
  • 열거자.

:: 의 왼쪽에 아무것도 없으면, lookup은 전역 네임스페이스 스코프 에 있는 선언만 고려합니다. 이는 해당 이름들이 지역 선언에 의해 가려져 있는 경우에도 그러한 이름들을 참조할 수 있게 합니다:

#include <iostream>
namespace M {
    const char* fail = "fail\n";
}
using M::fail;
namespace N {
    const char* ok = "ok\n";
}
using namespace N;
int main()
{
    struct std {};
    std::cout << ::fail; // 오류: 'std'에 대한 비한정 검색이 구조체를 찾음
    ::std::cout << ::ok; // 정상: ::std가 네임스페이스 std를 찾음
}

오른쪽 피연산자에 있는 이름에 대해 이름 검색(name lookup)이 수행되기 전에, 왼쪽 피연산자에 있는 이름에 대한 검색이 완료되어야 합니다( decltype 표현식이 사용되거나 왼쪽에 아무것도 없는 경우는 제외). 이 검색은 해당 이름 왼쪽에 또 다른 :: 가 있는지 여부에 따라 한정된(qualified) 또는 비한정된(unqualified) 검색일 수 있으며, 네임스페이스, 클래스 타입, 열거형(enumeration), 그리고 특수화가 타입인 템플릿만을 고려합니다. 왼쪽에서 발견된 이름이 네임스페이스나 클래스, 열거형, 종속 타입(dependent type)을 지정하지 않으면 프로그램은 올바르지 않습니다(ill-formed):

struct A
{
    static int n;
};
int main()
{
    int A;
    A::n = 42; // OK: :: 왼쪽의 비한정 이름 검색은 변수를 무시함
    A b;       // 오류: A의 비한정 이름 검색이 변수 A를 찾음
}
template<int>
struct B : A {};
namespace N
{
    template<int>
    void B();
    int f()
    {
        return B<0>::n; // 오류: N::B<0>은 타입이 아님
    }
}

한정된 이름이 선언자 로 사용될 때, 동일한 선언자 내에서 해당 한정된 이름 뒤에 오는 이름들에 대한 비한정 이름 검색 은 해당 멤버의 클래스나 네임스페이스 범위에서 수행되지만, 그 앞에 오는 이름들에 대해서는 수행되지 않습니다:

class X {};
constexpr int number = 100;
struct C
{
    class X {};
    static const int number = 50;
    static X arr[number];
};
X C::arr[number], brr[number];    // 오류: X를 찾을 때 ::X를 찾고 C::X를 찾지 않음
C::X C::arr[number], brr[number]; // 정상: arr의 크기는 50, brr의 크기는 100

만약 :: 다음에 ~ 문자가 오고, 그 다음에 식별자가 오는 경우(즉, 소멸자나 의사 소멸자를 지정하는 경우), 해당 식별자는 :: 왼쪽에 있는 이름과 동일한 범위에서 조회됩니다.

struct C { typedef int I; };
typedef int I1, I2;
extern int *p, *q;
struct A { ~A(); };
typedef A AB;
int main()
{
    p->C::I::~I(); // ~ 다음의 이름 I는 :: 앞의 I와 동일한 범위에서 조회됩니다
                   // (즉, C의 범위 내에서 조회하므로 C::I를 찾습니다)
    q->I1::~I2();  // 이름 I2는 I1과 동일한 범위에서 조회됩니다
                   // (즉, 현재 범위에서 조회하므로 ::I2를 찾습니다)
    AB x;
    x.AB::~AB();   // ~ 다음의 이름 AB는 :: 앞의 AB와 동일한 범위에서 조회됩니다
                   // (즉, 현재 범위에서 조회하므로 ::AB를 찾습니다)
}

목차

열거자

왼쪽 피연산자 이름의 조회 결과가 열거형 (범위가 지정되었거나 지정되지 않은)인 경우, 오른쪽 피연산자의 조회 결과는 해당 열거형에 속하는 열거자여야 합니다. 그렇지 않으면 프로그램은 잘못된 형식입니다.

(C++11부터)

클래스 멤버

왼쪽 피연산자 이름의 조회가 클래스/구조체 또는 공용체 이름으로 확인되면, :: 오른쪽 피연산자의 이름은 해당 클래스의 범위에서 조회되며(따라서 해당 클래스나 그 기본 클래스의 멤버 선언을 찾을 수 있음), 다음과 같은 예외가 적용됩니다:

  • 소멸자는 위에서 설명한 대로 (:: 왼쪽에 있는 이름의 범위에서) 조회됩니다.
  • 사용자 정의 변환 함수 이름의 conversion-type-id는 먼저 클래스 범위에서 조회됩니다. 찾을 수 없는 경우, 현재 범위에서 이름을 조회합니다.
  • 템플릿 인수에서 사용되는 이름들은 현재 범위에서 조회됩니다 (템플릿 이름의 범위가 아닙니다).
  • using-선언 에서의 이름들은 동일한 범위에서 선언된 변수, 데이터 멤버, 함수 또는 열거자 이름에 의해 가려진 클래스/열거형 이름들도 고려합니다.

:: 의 우변에서 명시하는 클래스가 좌변과 동일한 경우, 해당 이름은 그 클래스의 생성자 를 지칭합니다. 이러한 한정된 이름은 생성자 선언과 using 선언 에서 상속 생성자 를 위해 사용될 수 있습니다. 함수 이름이 무시되는 조회 상황(즉, :: 의 좌측에서 이름을 조회할 때, 정교화된 타입 지정자 에서 이름을 조회할 때, 또는 기반 클래스 지정자 에서 조회할 때)에서는 동일한 구문이 주입된 클래스 이름으로 해석됩니다:

struct A { A(); };
struct B : A { B(); };
A::A() {} // A::A는 생성자를 지칭하며, 선언에서 사용됨
B::B() {} // B::B는 생성자를 지칭하며, 선언에서 사용됨
B::A ba;  // B::A는 타입 A를 지칭함 (B의 스코프에서 조회됨)
A::A a;   // 오류: A::A는 타입을 지칭하지 않음
struct A::A a2; // OK: 정교화된 타입 지정자에서의 조회는 함수를 무시함
                // 따라서 A::A는 단순히 A 스코프 내에서 보이는 클래스 A를 지칭함
                // (즉, 주입된 클래스 이름)

한정된 이름 조회(Qualified name lookup)는 중첩 선언이나 파생 클래스에 의해 가려진 클래스 멤버에 접근하는 데 사용될 수 있습니다. 한정된 멤버 함수에 대한 호출은 절대 가상(virtual)이 아닙니다:

struct B { virtual void foo(); };
struct D : B { void foo() override; };
int main()
{
    D x;
    B& b = x;
    b.foo();    // D::foo 호출 (가상 디스패치)
    b.B::foo(); // B::foo 호출 (정적 디스패치)
}

네임스페이스 멤버

:: 왼쪽의 이름이 네임스페이스를 참조하거나 :: 왼쪽에 아무것도 없는 경우(이 경우 전역 네임스페이스를 참조함), :: 오른쪽에 나타나는 이름은 해당 네임스페이스의 스코프에서 조회되지만, 다음 경우는 예외입니다.

  • 템플릿 인자에 사용된 이름들은 현재 스코프에서 조회됩니다:
namespace N
{
    template<typename T>
    struct foo {};
    struct X {};
}
N::foo<X> x; // 오류: X는 N::X가 아닌 ::X로 조회됨

네임스페이스 N 범위 내에서의 정규화된 조회는 먼저 N 에 위치한 모든 선언과 N 인라인 네임스페이스 멤버 에 위치한 모든 선언(그리고 전이적으로, 그들의 인라인 네임스페이스 멤버들)을 고려합니다. 해당 집합에 선언이 없는 경우, N N 의 모든 전이적 인라인 네임스페이스 멤버들에서 발견되는 using-directives 로 명명된 모든 네임스페이스들의 선언들을 고려합니다. 이 규칙들은 재귀적으로 적용됩니다:

int x;
namespace Y
{
    void f(float);
    void h(int);
}
namespace Z
{
    void h(double);
}
namespace A
{
    using namespace Y;
    void f(int);
    void g(int);
    int i;
}
namespace B
{
    using namespace Z;
    void f(char);
    int i;
}
namespace AB
{
    using namespace A;
    using namespace B;
    void g();
}
void h()
{
    AB::g();  // AB를 검색하고, 조회를 통해 AB::g를 찾아 선택됨 AB::g(void)
              // (A와 B는 검색되지 않음)
    AB::f(1); // 먼저 AB를 검색. f가 없음
              // 그 다음 A, B를 검색
              // 조회를 통해 A::f, B::f를 찾음
              // (하지만 Y는 검색되지 않으므로 Y::f는 고려되지 않음)
              // 오버로드 해결이 A::f(int)를 선택
    AB::x++;  // 먼저 AB를 검색. x가 없음
              // 그 다음 A, B를 검색. x가 없음
              // 그 다음 Y와 Z를 검색. 여전히 x가 없음: 이는 오류
    AB::i++;  // AB를 검색. i가 없음
              // 그 다음 A, B를 검색. 조회를 통해 A::i와 B::i를 찾음: 이는 오류
    AB::h(16.8); // 먼저 AB를 검색. h가 없음
                 // 그 다음 A, B를 검색. h가 없음
                 // 그 다음 Y와 Z를 검색
                 // 조회를 통해 Y::h와 Z::h를 찾음. 오버로드 해결이 Z::h(double)을 선택
}

동일한 선언이 두 번 이상 발견되는 것이 허용됩니다:

namespace A { int a; }
namespace B { using namespace A; }
namespace D { using A::a; }
namespace BD
{
    using namespace B;
    using namespace D;
}
void g()
{
    BD::a++; // 정상: B와 D를 통해 동일한 A::a를 찾음
}

결함 보고서

다음의 동작 변경 결함 보고서들은 이전에 발표된 C++ 표준에 소급 적용되었습니다.

DR 적용 대상 게시된 동작 올바른 동작
CWG 215 C++98 :: 앞의 이름은 클래스 이름이나 네임스페이스
이름이어야 했으므로 템플릿 매개변수는 허용되지 않았음
해당 이름은 클래스, 네임스페이스
또는 종속 타입을 지정해야 함
CWG 318 C++98 :: 오른쪽이 왼쪽과 동일한 클래스를
지정하는 경우, 한정된 이름은 항상
해당 클래스의 생성자로 간주됨
허용 가능한 경우에만 생성자로 지정
(예: 상세 타입 지정자에서는 아님)

참고 항목