Namespaces
Variants

Scope

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

C++ 프로그램에 나타나는 각 선언 은 일부 불연속적인 스코프  에서만 보입니다.

범위 내에서, 비한정 이름 조회(unqualified name lookup) 를 사용하여 이름을 해당 선언과 연결할 수 있습니다.

목차

일반

각 프로그램은 전역 범위(global scope)  를 가지며, 이는 전체 프로그램을 포함합니다 .

다른 모든 범위 S 는 다음 중 하나에 의해 도입됩니다:

(C++26부터)

S 는 항상 다른 스코프에 나타나며, 이로 인해 해당 스코프가 포함하는 S 가 됩니다.

프로그램 지점에서의 enclosing scope 는 해당 지점을 포함하는 모든 범위를 의미합니다; 이러한 범위 중 가장 작은 범위는 해당 지점에서의 immediate scope 라고 합니다.

스코프가 프로그램 포인트 P 와 스코프 S ( P 를 포함하지 않는) 사이에 개입한다 는 것은, 해당 스코프가 S 와 동일하거나 S 를 포함하지만 P 를 포함하지 않는 경우를 말합니다.

parent scope 이 아닌 모든 스코프 S template parameter scope parent scope S 를 포함하고 template parameter scope가 아닌 가장 작은 스코프입니다.

달리 명시되지 않는 한:

  • 선언은 그 locus 에서 바로 해당 scope를 차지합니다 .
  • 선언의 target scope 는 그것이 차지하는 scope입니다.
  • 선언에 의해 (재)도입된 모든 이름들은 그 target scope에서 선언에 bound 됩니다.

엔터티는 속한다 해당 스코프 S 에, 만약 S 가 해당 엔터티의 선언 대상 스코프인 경우.

//                global  scope  scope
//                scope     S      T
int x;         //   ─┐                 // 프로그램 포인트 X
               //    │
{              //    │     ─┐
    {          //    │      │     ─┐
        int y; //    │      │      │   // 프로그램 포인트 Y
    }          //    │      │     ─┘
}              //   ─┘     ─┘

위 프로그램에서:

  • 전역 범위, 범위 S 및 범위 T 는 프로그램 포인트 Y 를 포함합니다.
  • 다시 말해, 이 세 가지 범위는 모두 프로그램 지점 Y 에서의 둘러싸는 범위입니다.
  • 전역 범위는 S T 범위를 포함하며, S 범위는 T 범위를 포함합니다.
  • 따라서 스코프 T 는 세 가지 중 가장 작은 스코프이며, 이는 다음을 의미합니다:
  • 스코프 T 는 프로그램 포인트 Y 에서의 직접적인 스코프입니다.
  • 변수 y 의 선언은 해당 위치에서 스코프 T 에 속합니다.
  • 스코프 T y 선언의 대상 스코프입니다.
  • 변수 y 는 스코프 T 에 속합니다.
  • 스코프 S 는 스코프 T 의 부모 스코프이며, 전역 스코프는 스코프 S 의 부모 스코프입니다.
  • 스코프 S 가 프로그램 포인트 X 와 스코프 T 사이에서 개입합니다.

블록 범위

각각

문장이나 핸들러를 포함하는 block scope 를 도입합니다.

블록 범위에 속하는 변수는 블록 변수 (지역 변수라고도 함)입니다.

int i = 42;
int a[10];
for (int i = 0; i < 10; i++) // 내부 "i"는 블록 범위를 차지함
    a[i] = i;                // for 문에 의해 도입됨
int j = i; // j = 42

선언이 블록 범위 S 에 속하고 함수를 선언하거나 extern 지정자를 사용하는 경우 , 해당 선언은 named module  에 부착되어서는 안 되며 (C++20부터) , 그 대상 범위는 더 큰 외부 범위(가장 안쪽의 네임스페이스 범위)이지만, 이름은 바로 해당 범위 S 에 바인딩됩니다.

선언이 이름 독립적 선언 이 아니고 (since C++26) 블록 범위 S 에서 이름을 바인딩하는 경우

  • 함수 본문 또는 함수 try 블록의 복합문(compound-statement) ,
(C++11부터)
  • 선택문이나 반복문의 하위 문장이면서 그 자체가 선택문이나 반복문이 아닌 경우, 또는
  • 함수 try 블록의 핸들러

잠재적으로 충돌하는 선언의 대상 범위가 S 의 부모 범위인 경우, 프로그램은 올바르지 않습니다.

if (int x = f())  // "x"를 선언
{ // if 블록은 if 문의 하위 문입니다
    int x;        // 오류: "x"의 재선언
}
else
{ // else 블록 또한 if 문의 하위 문입니다
    int x;        // 오류: "x"의 재선언
}
void g(int i)
{
    extern int i; // 오류: "i"의 재선언
}

함수 매개변수 범위

매개변수 선언 P 함수 매개변수 범위 를 도입하며, 이 범위는 P 를 포함합니다.

  • 선언된 매개변수가 함수 선언 의 매개변수 목록에 속하는 경우:
  • 함수 선언이 함수 정의 인 경우, 도입된 범위는 함수 정의의 끝까지 확장됩니다.
  • 그렇지 않은 경우(함수 선언이 함수 프로토타입인 경우), 도입된 범위는 함수 선언자의 끝까지 확장됩니다.
  • 두 경우 모두, 범위는 함수 선언의 locus 를 포함하지 않습니다.
  • 선언된 매개변수가 람다 표현식 의 매개변수 목록에 속하는 경우, 도입된 스코프는 { body } 의 끝까지 확장됩니다.
(since C++11)
  • 선언된 매개변수가 deduction guide 의 매개변수 목록에 속하는 경우, 도입된 스코프는 해당 deduction guide의 끝까지 확장됩니다.
(since C++17)
  • 선언된 매개변수가 requires expression 의 매개변수 목록에 속하는 경우, 도입된 스코프는 { requirement-seq } 의 끝까지 확장됩니다.
(since C++20)
int f(int n) // 매개변수 "n"의 선언
{            // 함수 매개변수 범위를 도입함
    /* ... */
}            // 함수 매개변수 범위가 여기서 종료됨

람다 스코프

람다 표현식 [ 캡처  ] 바로 다음부터 시작하여 { 본문 } 끝까지 확장되는 람다 스코프 를 도입합니다.

람다 표현식 E 캡처 와 초기화자는 E 에 의해 도입된 람다 스코프에 속합니다.

auto lambda = [x = 1, y]() // 이 람다 표현식은 람다 스코프를 도입하며,
{                          // 이는 캡처 "x"의 대상 스코프입니다
    /* ... */
};                         // 람다 스코프는 세미콜론 전에 종료됩니다
(C++14부터)

네임스페이스 범위

모든 namespace 정의 N 네임스페이스에 대해 namespace scope S 를 도입하며, 이 스코프는 N 에 대한 모든 네임스페이스 정의의 declarations 를 포함합니다.

비-프렌드 재선언 또는 특수화 각각에 대해, 대상 범위가 S 이거나 S 에 포함되는 경우, 다음 부분들도 범위 S 에 포함됩니다:

  • class (템플릿) 재선언 또는 클래스 템플릿 특수화의 경우, class-head-name 이후 부분.
  • enumeration 재선언의 경우, enum-head-name 이후 부분.
  • 다른 모든 재선언 또는 특수화의 경우, declarator unqualified-id 또는 qualified-id 이후 부분.

전역 범위(global scope) 전역 네임스페이스(global namespace) 의 네임스페이스 범위입니다.

namespace V   // 네임스페이스 "V"의 정의
{             // 네임스페이스 스코프 "S"를 시작함
    // 스코프 "S"의 첫 번째 부분이 여기서 시작됨
    void f();
    // 스코프 "S"의 첫 번째 부분이 여기서 끝남
}
void V::f()   // "f" 이후 부분도 스코프 "S"의 일부임
{
    void h(); // V::h를 선언함
}             // 스코프 "S"의 두 번째 부분이 여기서 끝남

클래스 범위

클래스 또는 클래스 템플릿 C 의 각 선언은 C 클래스 정의 멤버 명세 를 포함하는 클래스 범위 S 를 도입합니다.

비-프렌드 재선언 또는 특수화 각각에 대해, 대상 범위가 S 이거나 S 에 포함되는 경우, 다음 부분들도 범위 S 에 포함됩니다:

  • class (템플릿) 재선언 또는 클래스 템플릿 특수화의 경우, class-head-name 이후 부분.
  • enumeration 재선언의 경우, enum-head-name 이후 부분.
  • 다른 모든 재선언 또는 특수화의 경우, declarator unqualified-id 또는 qualified-id 이후 부분.
class C       // "C" 클래스 정의
{             // 클래스 스코프 "S" 시작
    // 스코프 "S"의 첫 번째 부분 시작
    void f();
    // 스코프 "S"의 첫 번째 부분 종료
}
void C::f()   // "f" 이후 부분도 스코프 "S"의 일부
{
    /* ... */
}             // 스코프 "S"의 두 번째 부분 종료

열거형 범위

열거형 E 의 각 선언은 E 열거형 선언 비불투명 (C++11부터) 열거자-목록 을 포함하는 열거형 범위 를 도입합니다 (존재하는 경우).

enum class E // "E"의 열거형 선언
{            // 열거형 범위 "S"를 도입함
    // 범위 "S"가 여기서 시작됨
    e1, e2, e3
    // 범위 "S"가 여기서 종료됨
}

템플릿 매개변수 범위

template template parameter 는 해당 template template parameter의 전체 템플릿 매개변수 목록 require clauses (C++20부터) 을 포함하는 template parameter scope 를 도입합니다.

각 템플릿 선언 D 템플릿 매개변수 범위 S 를 도입하며, 이 범위는 D 의 템플릿 매개변수 목록 시작부터 D 의 끝까지 확장됩니다. 템플릿 매개변수 목록 외부에 선언되어 S 에 속하게 될 선언은 대신 D 와 동일한 범위에 속하게 됩니다.

템플릿 매개변수만이 템플릿 매개변수 범위에 속하며, 템플릿 매개변수 범위만이 부모 범위로 템플릿 매개변수 범위를 가집니다.

// "X"의 클래스 템플릿 선언
// 템플릿 매개변수 범위 "S1"을 도입함
template
<
    // 범위 "S1"이 여기서 시작함
    template // 템플릿 템플릿 매개변수 "T"는
             // 또 다른 템플릿 매개변수 범위 "S2"를 도입함
    <
        typename T1
        typename T2
    > requires std::convertible_from<T1, T2> // 범위 "S2"가 여기서 끝남
    class T,
    typename U
>
class X; // 범위 "S1"이 세미콜론 앞에서 끝남
namespace N
{
    template <typename T>
    using A = struct X; // "X"는 템플릿 선언과 동일한 범위,
                        // 즉 "N"의 범위에 위치함
}

계약 어서션 범위

계약 어서션 C 계약 어서션 범위 를 도입하며, 이 범위는 C 를 포함합니다.

만약 사후 조건 어서션 식별자 를 가지고 있고, 이 식별자가 이름 독립적 이 아니며, 사후 조건 어서션이 함수 func 와 연관되어 있고, 잠재적 충돌 이 있는 선언 D 의 대상 범위가 다음 중 하나인 경우, 프로그램은 ill-formed입니다:

  • 함수 func 의 매개변수 범위
  • 만약 D 람다 표현식 과 연관되어 있다면, 사전 조건 어서션의 가장 가까운 둘러싸는 람다 범위
(C++26부터)

선언 지점

일반적으로, 이름은 다음과 같이 위치하는 첫 번째 선언의 locus 이후에 표시됩니다.

단순 선언에서 선언된 이름의 위치는 해당 이름의 declarator 바로 뒤이며, 초기화자가 있을 경우 그 앞입니다.

int x = 32; // 외부 x가 스코프 내에 있음
{
    int x = x; // 내부 x는 초기화자(= x) 이전에 스코프 내에 있음
               // 이는 내부 x를 외부 x의 값(32)으로 초기화하지 않고,
               // 내부 x를 자신의 (불확정) 값으로 초기화함
}
std::function<int(int)> f = [&](int n){ return n > 1 ? n * f(n - 1) : n; };
// 함수 f의 이름은 람다 내에서 스코프에 있으며
// 참조로 올바르게 캡처되어 재귀 함수를 제공할 수 있음
const int x = 2; // 외부 x가 scope 내에 있음
{
    int x[x] = {}; // 내부 x는 초기화자 (= {}) 이전에 scope 내에 있지만,
                   // 선언자 (x[x]) 이후에 scope 내에 있음
                   // 선언자에서는 외부 x가 여전히 scope 내에 있음
                   // 이는 2개의 int를 가진 배열을 선언함
}

클래스 또는 클래스 템플릿 선언의 locus는 해당 클래스의 이름을 지정하는 식별자(또는 템플릿 특수화를 지정하는 template-id ) 바로 뒤에 위치합니다. 클래스 또는 클래스 템플릿 이름은 기본 클래스 목록에서 이미 scope 내에 있습니다.

struct S: std::enable_shared_from_this<S> {}; // 콜론 위치에서 S는 스코프 내에 있습니다

enum 지정자 또는 불투명 enum 선언 (C++11부터) 의 위치는 열거형을 명명하는 식별자 바로 뒤입니다.

enum E : int // 콜론에서 E는 스코프 내에 있음
{
    A = sizeof(E)
};

type alias 또는 alias template 선언의 위치는 해당 alias가 참조하는 type-id 바로 뒤입니다.

using T = int; // 세미콜론에서 외부 T가 유효 범위 내에 있음
{
    using T = T*; // 세미콜론에서 내부 T가 유효 범위 내에 있음,
                  // 세미콜론 이전까지 외부 T도 여전히 유효 범위 내에 있음
                  // T = int*와 동일
}

using 선언 에서 생성자를 명시하지 않는 선언자의 위치는 선언자 바로 뒤입니다.

template<int N>
class Base
{
protected:
    static const int next = N + 1;
    static const int value = N;
};
struct Derived: Base<0>, Base<1>, Base<2>
{
    using Base<0>::next,     // next가 쉼표 위치에서 스코프 내에 있음
          Base<next>::value; // Derived::value는 1
};

열거자(Enumerator)의 위치는 정의 직후입니다(변수에서 초기화 이전인 경우와 다릅니다).

const int x = 12;
{
    enum
    {
        x = x + 1, // 열거자 x는 쉼표에서 스코프 내에 있음,
                   // 외부 x는 쉼표 이전에 스코프 내에 있음,
                   // 열거자 x는 13으로 초기화됨
        y = x + 1  // y는 14로 초기화됨
    };
}

injected-class-name 의 locus는 해당 클래스(또는 클래스 템플릿) 정의의 여는 중괄호 바로 뒤에 위치합니다.

template<typename T>
struct Array
//  : std::enable_shared_from_this<Array> // 오류: 주입된 클래스 이름이 범위 내에 없음
    : std::enable_shared_from_this< Array<T> > // OK: 템플릿 이름 Array가 범위 내에 있음
{ // 주입된 클래스 이름 Array는 이제 public 멤버 이름처럼 범위 내에 있음
    Array* p; // Array<T>를 가리키는 포인터
};

함수-지역 사전 정의 변수 __func__ 에 대한 암시적 선언의 위치는 함수 정의의 함수 본문 바로 앞입니다.

(since C++11)


구조화된 바인딩 선언 의 유효 범위는 identifier-list 바로 뒤에서 시작되지만, 구조화된 바인딩 초기화자는 선언되는 이름 중 어떤 것도 참조하는 것이 금지됩니다.

(C++17부터)


범위 기반 for 루프 range-declaration 에서 선언된 변수 또는 구조화된 바인딩 (C++17부터) 의 범위는 range-expression 바로 다음부터 시작됩니다.

std::vector<int> x;
for (auto x : x) // 벡터 x는 닫는 괄호 전까지 범위에 있음,
                 // auto x는 닫는 괄호에서 범위에 들어감
{
    // auto x가 범위 내에 있음
}
(C++11부터)

템플릿 매개변수의 위치는 template parameter 의 완전한 템플릿 매개변수(선택적 기본 인자를 포함하여) 바로 뒤입니다.

typedef unsigned char T;
template<
    class T = T, // 쉼표에서 템플릿 매개변수 T가 유효 범위 내에 있음,
                 // 쉼표 이전에는 unsigned char의 typedef 이름이 유효 범위 내에 있음
    T // 템플릿 매개변수 T가 유효 범위 내에 있음
    N = 0
>
struct A
{
};

사후 조건 단언문 의 위치는 해당 식별자의 : 바로 뒤입니다.

(since C++26)


concept 정의 의 locus는 concept 이름 바로 뒤에 위치하지만, concept 정의는 선언 중인 concept 이름을 참조하는 것이 금지됩니다.

(since C++20)

명명된 namespace definition 의 locus는 네임스페이스 이름 바로 뒤입니다.

결함 보고서

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

DR 적용 대상 게시된 동작 올바른 동작
CWG 2793 C++98 블록 범위에서의 extern 선언이 상위 범위의 다른 선언과
충돌할 수 있었음
금지됨

참조문헌

  • C++23 표준 (ISO/IEC 14882:2024):
  • 6.4 범위 [basic.scope]
  • C++20 표준 (ISO/IEC 14882:2020):
  • 6.4 범위 [basic.scope]
  • C++17 표준 (ISO/IEC 14882:2017):
  • 6.3 범위 [basic.scope]
  • C++14 표준(ISO/IEC 14882:2014):
  • 3.3 범위 [basic.scope]
  • C++11 표준 (ISO/IEC 14882:2011):
  • 3.3 범위 [basic.scope]
  • C++98 표준(ISO/IEC 14882:1998):
  • 3.3 선언 영역과 범위 [basic.scope]

참고 항목

C 문서 for Scope