Declarations
선언(Declarations) 은 이름이 C++ 프로그램에 도입(또는 재도입)되는 방법입니다. 모든 선언이 실제로 무언가를 선언하는 것은 아니며, 각 종류의 엔터티는 서로 다르게 선언됩니다. 정의(Definitions) 는 이름으로 식별되는 엔터티를 사용하기에 충분한 선언입니다.
선언은 다음 중 하나입니다:
|
(C++11부터) |
-
빈 선언 (
;) - decl-specifier-seq 없이 이루어진 함수 선언:
attr
(선택 사항)
declarator
;
|
|||||||||
| attr | - | (since C++11) 임의 개수의 attributes 시퀀스 |
| declarator | - | 함수 선언자 |
- 이 선언은 생성자, 소멸자, 또는 사용자 정의 타입 conversion function 을 선언해야 합니다. 이것은 template declaration , explicit specialization , 또는 explicit instantiation의 일부로만 사용될 수 있습니다.
- block-declaration (블록 내부에 나타날 수 있는 선언으로, 이는 다음 중 하나일 수 있음):
| (C++11부터) |
| (C++20부터) | |
| (C++11부터) |
-
- 단순 선언
목차 |
단순 선언
단순 선언은 하나 이상의 식별자(일반적으로 변수)를 도입하고 생성하며, 선택적으로 초기화하는 문장입니다.
decl-specifier-seq
init-declarator-list
(선택적)
;
|
(1) | ||||||||
attr
decl-specifier-seq
init-declarator-list
;
|
(2) | (C++11 이후) | |||||||
| decl-specifier-seq | - | 지정자 의 시퀀스 |
| init-declarator-list | - | init-declarator 들의 쉼표로 구분된 목록 (아래 참조) |
| attr | - | 임의 개수의 속성 시퀀스 |
init-declarator-list
는 명명된 클래스 또는 명명된 열거형을 선언할 때만 생략할 수 있습니다.
|
구조화된 바인딩 선언 또한 단순 선언입니다. |
(C++17부터) |
init-declarator
의 구문은 다음과 같이 정의됩니다:
| declarator initializer | (1) | ||||||||
| declarator requires-clause (선택적) contract-specs (선택적) | (2) | ||||||||
| declarator | - | a declarator |
| initializer | - | an initializer |
| requires-clause | - | (since C++20) a requires clause |
| contract-specs | - | (since C++26) a list of function contract specifiers |
|
requires-clause 는 declarator 가 템플릿 함수 를 선언하는 경우에만 나타날 수 있습니다. |
(C++20부터) |
|
contract-specs 는 declarator 가 함수 또는 함수 템플릿을 선언하는 경우에만 나타날 수 있습니다. |
(C++26부터) |
지정자
선언 지정자 ( decl-specifier-seq )는 다음의 공백으로 구분된 지정자들이 임의의 순서로 나열된 시퀀스입니다:
-
typedef지정자. 만약 존재한다면, 전체 선언은 typedef 선언 이며 각 선언자는 객체나 함수가 아닌 새로운 타입 이름을 도입합니다. -
함수 지정자 (
inline,virtual,explicit), 함수 선언 에서만 허용됩니다.
|
(C++17부터) |
-
friend지정자는 클래스 및 함수 선언에서 허용됩니다.
|
(C++11부터) |
| (C++20부터) |
- 저장 클래스 지정자 ( register , (C++17까지) static , thread_local , (C++11부터) extern , mutable ). 오직 하나의 저장 클래스 지정자만 허용됨 , 단 thread_local 은 extern 또는 static 과 함께 나타날 수 있음 (C++11부터) .
- 타입 지정자 ( type-specifier-seq ), 타입을 명명하는 지정자들의 시퀀스. 선언에 의해 도입된 모든 엔티티의 타입은 이 타입이며, 선택적으로 선언자에 의해 수정될 수 있음(아래 참조). 이 지정자 시퀀스는 type-id 에서도 사용됨. 다음 지정자들만이 type-specifier-seq 의 일부이며, 임의의 순서로 나타날 수 있음:
| (C++11 이후) | |
| (C++26 이후) |
-
-
- 이전에 선언된 클래스 이름 (선택적으로 qualified )
- 이전에 선언된 enum 이름 (선택적으로 qualified )
- 이전에 선언된 typedef-name 또는 type alias (C++11부터) (선택적으로 qualified )
- 템플릿 인자를 가진 템플릿 이름 (선택적으로 qualified , 선택적으로 template disambiguator 사용)
-
|
(C++17부터) |
-
-
decl-specifier-seq에서는 하나의 타입 지정자만 허용되며, 다음 예외가 적용됩니다:
- const 는 자기 자신을 제외한 모든 타입 지정자와 결합할 수 있습니다.
- volatile 는 자기 자신을 제외한 모든 타입 지정자와 결합할 수 있습니다.
- signed 또는 unsigned 는 char , long , short , 또는 int 와 결합할 수 있습니다.
- short 또는 long 는 int 와 결합할 수 있습니다.
- long 는 double 와 결합할 수 있습니다.
|
(C++11부터) |
속성 은 decl-specifier-seq 에 나타날 수 있으며, 이 경우 앞에 나온 지정자들에 의해 결정된 타입에 적용됩니다.
decl-specifier-seq 내에서의 모든 지정자 반복, 예를 들어 const static const 또는 virtual inline virtual 는 오류입니다 , 단 long 이 두 번 나타나는 것은 허용됨 (C++11부터) .
선언자
init-declarator-list 내의 각 init-declarator 는 동일한 지정자를 가진 독립 선언문처럼 처리됩니다: S D1, D2, D3 ; 는 다음과 같이 처리됩니다: S D1 ; S D2 ; S D3 ; .
각 선언자는 정확히 하나의 객체, 참조, 함수, 또는 (typedef 선언의 경우) 타입 별칭을 도입하며, 그 타입은 decl-specifier-seq 에 의해 제공되고 선언자 내에서 & (참조)나 [ ] (배열) 또는 ( ) (함수 반환)과 같은 연산자들에 의해 선택적으로 수정될 수 있습니다. 이러한 연산자들은 아래에 보여지는 것처럼 재귀적으로 적용될 수 있습니다.
선언자는 다음 중 하나입니다:
| unqualified-id attr (선택 사항) | (1) | ||||||||
| qualified-id attr (선택 사항) | (2) | ||||||||
...
identifier
attr
(선택 사항)
|
(3) | (C++11 이후) | |||||||
*
attr
(선택 사항)
cv
(선택 사항)
declarator
|
(4) | ||||||||
nested-name-specifier
*
attr
(선택 사항)
cv
(선택 사항)
declarator
|
(5) | ||||||||
&
attr
(선택 사항)
declarator
|
(6) | ||||||||
&&
attr
(선택 사항)
declarator
|
(7) | (C++11 이후) | |||||||
noptr-declarator
[
constant-expression
(선택 사항)
]
attr
(선택 사항)
|
(8) | ||||||||
noptr-declarator
(
parameter-list
)
cv
(선택 사항)
ref
(선택 사항)
except
(선택 사항)
attr
(선택 사항)
|
(9) | ||||||||
(
declarator
)
|
(10) | ||||||||
D
를
C
의 멤버 포인터로 선언하며, 그 타입은
decl-specifier-seq
S
에 의해 결정됩니다.
nested-name-specifier
는
이름과 범위 확인 연산자
::
의 시퀀스입니다
D
를
decl-specifier-seq
S
에 의해 결정된 타입에 대한 lvalue reference로 선언합니다.
D
를
decl-specifier-seq
S
에 의해 결정된 타입에 대한 rvalue 참조로 선언합니다.
|
모든 경우에서, attr 은 선택적인 attributes 시퀀스입니다. 식별자 바로 뒤에 나타날 때, 이는 선언되는 객체에 적용됩니다. |
(since C++11) |
cv 는 const 및 volatile 한정자들의 시퀀스이며, 각 한정자는 시퀀스 내에서 최대 한 번만 나타날 수 있습니다.
|
이 섹션은 불완전합니다
이유: 선언 이름 숨김 규칙 설명; 동일한 이름을 가진 클래스(typedef는 제외)를 변수/함수 선언이 어떻게 숨기는지 |
참고 사항
블록 내부에 block-declaration 이 나타날 때, 선언에 의해 도입된 식별자가 이전에 외부 블록에서 선언된 경우 외부 선언은 블록의 나머지 부분에 대해 숨겨집니다 .
자동 저장 기간을 가진 변수를 선언하는 선언문이 실행될 때 해당 변수가 초기화됩니다. 블록 내에서 선언된 모든 자동 변수는 블록을 벗어날 때 (블록이 어떻게 종료되든: exception , goto , 또는 블록 끝에 도달함) 초기화 순서의 역순으로 소멸됩니다.
예제
참고: 이 예제는 언어 문법 측면에서 몇 가지 복잡한 선언이 어떻게 파싱되는지 보여줍니다. 다른 널리 사용되는 기억법으로는: the spiral rule , inside-out 읽기, 그리고 declaration mirrors use 가 있습니다. 또한 https://cdecl.org 에 자동화된 파서도 있습니다.
#include <type_traits> struct S { int member; // decl-specifier-seq is "int" // declarator is "member" } obj, *pObj(&obj); // decl-specifier-seq is "struct S { int member; }" // declarator "obj" declares an object of type S // declarator "*pObj" declares a pointer to S, // and initializer "(&obj)" initializes it int i = 1, *p = nullptr, f(), (*pf)(double); // decl-specifier-seq is "int" // declarator "i" declares a variable of type int, // and initializer "= 1" initializes it // declarator "*p" declares a variable of type int*, // and initializer "= nullptr" initializes it // declarator "f()" declares (but doesn't define) // a function taking no arguments and returning int // declarator "(*pf)(double)" declares a pointer to function // taking double and returning int int (*(*var1)(double))[3] = nullptr; // decl-specifier-seq is "int" // declarator is "(*(*var1)(double))[3]" // initializer is "= nullptr" // 1. declarator "(*(*var1)(double))[3]" is an array declarator: // Type declared is: "(*(*var1)(double))" array of 3 elements // 2. declarator "(*(*var1)(double))" is a pointer declarator: // Type declared is: "(*var1)(double)" pointer to array of 3 elements // 3. declarator "(*var1)(double)" is a function declarator: // Type declared is: "(*var1)" function taking "(double)", // returning pointer to array of 3 elements. // 4. declarator "(*var1)" is a pointer declarator: // Type declared is: "var1" pointer to function taking "(double)", // returning pointer to array of 3 elements. // 5. declarator "var1" is an identifier. // This declaration declares the object var1 of type "pointer to function // taking double and returning pointer to array of 3 elements of type int" // The initializer "= nullptr" provides the initial value of this pointer. // C++11 alternative syntax: auto (*var2)(double) -> int (*)[3] = nullptr; // decl-specifier-seq is "auto" // declarator is "(*var2)(double) -> int (*)[3]" // initializer is "= nullptr" // 1. declarator "(*var2)(double) -> int (*)[3]" is a function declarator: // Type declared is: "(*var2)" function taking "(double)", returning "int (*)[3]" // ... int main() { static_assert(std::is_same_v<decltype(var1), decltype(var2)>); }
결함 보고서
다음의 동작 변경 결함 보고서들은 이전에 발표된 C++ 표준에 소급 적용되었습니다.
| DR | 적용 대상 | 게시된 동작 | 올바른 동작 |
|---|---|---|---|
| CWG 482 | C++98 | 재선언의 선언자에 한정자를 사용할 수 없었음 | 한정된 선언자 허용 |
| CWG 569 | C++98 | 단독 세미콜론은 유효한 선언이 아니었음 |
이는 빈 선언이며,
아무런 효과가 없음 |
| CWG 1830 | C++98 | decl-specifier-seq 내에서 함수 지정자의 반복이 허용됨 | 반복이 금지됨 |
참고 항목
|
C 문서
에 대한
선언
|