Scope
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사이에서 개입합니다.
블록 범위
각각
- 선택문 ( if , switch ),
- 반복문 ( for , 범위 기반 for (C++11부터) , while , do - while ),
- 핸들러 , 또는
- 복합문 중 핸들러의 compound-statement 가 아닌 것
문장이나 핸들러를 포함하는 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
를 포함합니다.
- 선언된 매개변수가 함수 선언 의 매개변수 목록에 속하는 경우:
|
(since C++11) |
|
(since C++17) |
|
(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"의 범위에 위치함 }
계약 어서션 범위
각
계약 어서션
만약
사후 조건 어서션
이
식별자
를 가지고 있고, 이 식별자가
이름 독립적
이 아니며, 사후 조건 어서션이 함수
func
와 연관되어 있고,
잠재적 충돌
이 있는 선언
|
(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는 네임스페이스 이름 바로 뒤입니다.
|
이 섹션은 불완전합니다
이유: [basic.scope.pdecl]의 나머지 부분 |
결함 보고서
다음의 동작 변경 결함 보고서들은 이전에 발표된 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
|