정교화된 타입 지정자
정교화된 타입 지정자 (Elaborated Type Specifier)
이미 선언된 클래스 이름(class, struct, union)이나 열거형 이름을 가리킬 때, 그 이름이 비타입 선언에 가려져 있어도 참조할 수 있게 해주는 지정자예요. 그리고 새 클래스 이름을 선언할 때도 쓸 수 있어요. "이건 타입이지 변수가 아니야"라고 컴파일러에 말해주는 역할을 한다고 보면 돼요.
출처: cppreference
본문
문법
class-key class-name (1)
enum enum-name (2)
class-key attr (optional) identifier ; (3)
class-key—class,struct,union중 하나.class-name— 이전에 선언된 클래스 타입의 이름(선택적으로 한정됨), 또는 아직 타입 이름으로 선언되지 않은 식별자.enum-name— 이전에 선언된 열거형 타입의 이름(선택적으로 한정됨).attr— (C++11 이후) 임의 개수의 속성.
- 클래스 타입을 위한 정교화된 타입 지정자.
- 열거형 타입을 위한 정교화된 타입 지정자.
- 정교화된 타입 지정자만으로 이루어진 선언은, 항상 그 선언을 포함하는 스코프에서
identifier가 이름인 클래스 타입을 선언해요.
불투명 열거형 선언(opaque enum declaration)은 형식 (3)과 비슷해 보이지만, 불투명 열거형 선언 후에는 그 열거형 타입이 완전한 타입이 돼요.
설명
형식 (3)은 정교화된 타입 지정자의 특수한 경우로, 보통 클래스의 **전방 선언(forward declaration)**이라고 불러요. 형식 (3)에 대한 설명은 전방 선언을 참고하고, 여기서는 형식 (1)과 (2)만 다룰게요.
정교화된 타입 지정자 안의 class-name이나 enum-name은 단순 식별자일 수도, **한정 식별자(qualified-id)**일 수도 있어요. 이름은 그 형태에 따라 비한정 이름 조회 또는 한정 이름 조회로 찾아봐요. 어느 쪽이든 비타입 이름은 고려하지 않아요.
class T
{
public:
class U;
private:
int U;
};
int main()
{
int T;
T t; // error: the local variable T is found
class T t; // OK: finds ::T, the local variable T is ignored
T::U* u; // error: lookup of T::U finds the private data member
class T::U* u; // OK: the data member is ignored
}
이름 조회로 이전에 선언된 타입 이름을 찾지 못했는데, 정교화된 타입 지정자가 class, struct, union(즉 enum이 아님)으로 시작하고 class-name이 비한정 식별자라면, 이 정교화된 타입 지정자는 class-name의 클래스 선언이며, 대상 스코프는 가장 가까운 둘러싼 네임스페이스 또는 블록 스코프예요.
template<typename T>
struct Node
{
struct Node* Next; // OK: lookup of Node finds the injected-class-name
struct Data* Data; // OK: declares type Data at global scope
// and also declares the data member Data
friend class ::List; // error: cannot introduce a qualified name
enum Kind* kind; // error: cannot introduce an enum
};
Data* p; // OK: struct Data has been declared
이름이 typedef 이름, 타입 별칭, 템플릿 타입 매개변수, 또는 별칭 템플릿 특수화를 가리킨다면 프로그램은 ill-formed예요. 그렇지 않으면 정교화된 타입 지정자는 단순 타입 지정자가 자신의 type-name을 도입하는 것과 같은 방식으로 그 이름을 선언에 도입해요.
template<typename T>
class Node
{
friend class T; // error: type parameter cannot appear in an elaborated type specifier;
// note that similar declaration `friend T;` is OK.
};
class A {};
enum b { f, t };
int main()
{
class A a; // OK: equivalent to 'A a;'
enum b flag; // OK: equivalent to 'b flag;'
}
정교화된 타입 지정자에 있는 class-key 또는 enum 키워드는 그 이름이 가리키는 선언의 종류와 일치해야 해요.
- 열거형 타입(스코프 있는지 없는지와 무관)을 가리키려면
enum키워드를 써야 해요. - union을 가리키려면
unionclass-key를 써야 해요. - 비-union 클래스 타입을 가리키려면
class또는structclass-key를 써야 해요 (여기서class와struct는 서로 바꿔 쓸 수 있어요).
enum class E { a, b };
enum E x = E::a; // OK
enum class E y = E::b; // error: 'enum class' cannot introduce an elaborated type specifier
struct A {};
class A a; // OK
템플릿 인자로 쓰일 때, class T는 이름이 T인 타입 템플릿 매개변수를 뜻해요. 정교화된 타입 지정자로 도입되는, 타입이 T인 이름 없는 비타입 매개변수가 아니에요.
키워드
class,
struct,
union,
enum
참고 문헌
- C++23 표준 (ISO/IEC 14882:2024): 6.5.6 Elaborated type specifiers [basic.lookup.elab], 9.2.9.4 Elaborated type specifiers [dcl.type.elab]
- C++20 표준 (ISO/IEC 14882:2020): 6.5.4 Elaborated type specifiers [basic.lookup.elab], 9.2.8.3 Elaborated type specifiers [dcl.type.elab]
- C++17 표준 (ISO/IEC 14882:2017): 6.4.4 Elaborated type specifiers [basic.lookup.elab], 10.1.7.3 Elaborated type specifiers [dcl.type.elab]
- C++14 표준 (ISO/IEC 14882:2014): 3.4.4 Elaborated type specifiers [basic.lookup.elab], 7.1.6.3 Elaborated type specifiers [dcl.type.elab]
- C++11 표준 (ISO/IEC 14882:2011): 3.4.4 Elaborated type specifiers [basic.lookup.elab], 7.1.6.3 Elaborated type specifiers [dcl.type.elab]
- C++98 표준 (ISO/IEC 14882:1998): 3.4.4 Elaborated type specifiers [basic.lookup.elab], 7.1.5.3 Elaborated type specifiers [dcl.type.elab]
참고: 이 절은 불완전해요. 이유: 아마도 9.1 [class.name]/2-3의 내용을 cpp/language/class에서 가져와야 함.