Injected-class-name
주입된 클래스 이름은 해당 클래스 범위 내에서 클래스의 비한정 이름입니다.
class template 에서, injected-class-name은 현재 템플릿을 참조하는 템플릿 이름으로 사용되거나, 현재 인스턴스화를 참조하는 클래스 이름으로 사용될 수 있습니다.
목차 |
설명
클래스 범위 에서 현재 클래스의 클래스 이름이나 현재 클래스 템플릿의 템플릿 이름은 마치 public 멤버 이름인 것처럼 취급됩니다; 이를 injected-class-name (주입된 클래스 이름)이라고 합니다. 이름의 선언 지점은 클래스(템플릿) 정의의 여는 중괄호 바로 뒤입니다.
int X; struct X { void f() { X* p; // OK, X는 injected-class-name입니다 ::X* q; // 오류: 이름 검색이 변수 이름을 찾아 구조체 이름을 가립니다 } }; template<class T> struct Y { void g() { Y* p; // OK, Y는 injected-class-name입니다 Y<T>* q; // OK, Y는 injected-class-name이지만 Y<T>는 아닙니다 } };
다른 멤버들과 마찬가지로, injected-class-name은 상속됩니다. private 또는 protected 상속이 있는 경우, 간접 기본 클래스의 injected-class-name이 파생 클래스에서 접근 불가능하게 될 수 있습니다.
struct A {}; struct B : private A {}; struct C : public B { A* p; // 오류: 삽입된 클래스 이름 A에 접근할 수 없음 ::A* q; // 정상, 삽입된 클래스 이름을 사용하지 않음 };
클래스 템플릿 내에서
클래스 템플릿의 주입된 클래스 이름은 템플릿 이름이나 타입 이름으로 사용될 수 있습니다.
다음 경우에 삽입된 클래스 이름은 클래스 템플릿 자체의 템플릿 이름으로 취급됩니다:
-
이는
<뒤에 옵니다. - 이는 template template argument 로 사용됩니다.
- 이는 friend class template 선언의 elaborated class specifier 에서 마지막 식별자입니다.
그렇지 않으면, 타입 이름으로 처리되며, 클래스 템플릿의 템플릿 매개변수가
<>
안에 포함된 템플릿 이름과 동일합니다.
template<template<class, class> class> struct A; template<class T1, class T2> struct X { X<T1, T2>* p; // OK, X는 템플릿 이름으로 처리됨 using a = A<X>; // OK, X는 템플릿 이름으로 처리됨 template<class U1, class U2> friend class X; // OK, X는 템플릿 이름으로 처리됨 X* q; // OK, X는 타입 이름으로 처리됨, X<T1, T2>와 동등함 };
클래스
템플릿 특수화
또는
부분 특수화
범위 내에서, 주입된 클래스 이름이 타입 이름으로 사용될 때, 이는 클래스 템플릿 특수화 또는 부분 특수화의 템플릿 인자를
<>
안에 포함시킨 템플릿 이름과 동등합니다.
template<> struct X<void, void> { X* p; // OK, X는 타입 이름으로 처리됨 (X<void, void>와 동일) template<class, class> friend class X; // OK, X는 템플릿 이름으로 처리됨 (기본 템플릿과 동일) X<void, void>* q; // OK, X는 템플릿 이름으로 처리됨 }; template<class T> struct X<char, T> { X* p, q; // OK, X는 타입 이름으로 처리됨 (X<char, T>와 동일) using r = X<int, int>; // OK, 다른 특수화를 명명하는 데 사용 가능 };
클래스 템플릿이나 클래스 템플릿 특수화의 injected-class-name은 스코프 내에 있는 한 템플릿 이름이나 타입 이름으로 사용될 수 있습니다.
template<> class X<int, char> { class B { X a; // 의미: X<int, char> template<class, class> friend class X; // 의미: ::X }; }; template<class T> struct Base { Base* p; // OK: Base는 Base<T>를 의미함 }; template<class T> struct Derived : public Base<T*> { typename Derived::Base* p; // OK: Derived::Base는 Derived<T>::Base를 의미하며, // 이는 Base<T*>임 }; template<class T, template<class> class U = T::template Base> struct Third {}; Third<Derived<int>> t; // OK: 기본 인자가 템플릿으로서 주입된 클래스 이름을 사용함
주입된 클래스 이름을 찾는 조회는 특정 경우에 모호성을 초래할 수 있습니다(예: 둘 이상의 기본 클래스에서 발견되는 경우). 발견된 모든 주입된 클래스 이름이 동일한 클래스 템플릿의 특수화를 참조하고, 해당 이름이 템플릿-이름으로 사용되는 경우, 참조는 클래스 템플릿 자체를 가리키며 특수화를 가리키지 않으므로 모호하지 않습니다.
template<class T> struct Base {}; template<class T> struct Derived: Base<int>, Base<char> { typename Derived::Base b; // 오류: 모호함 typename Derived::Base<double> d; // 정상 };
인젝티드 클래스 이름과 생성자
생성자는 이름을 가지지 않지만, 둘러싸는 클래스의 주입된 클래스 이름(injected-class-name)은 생성자 선언과 정의에서 생성자를 명명하는 것으로 간주됩니다.
한정된 이름
C::D
에서, 만약
- 이름 검색(name lookup)은 함수 이름을 무시하지 않으며,
-
클래스
C의 범위(scope)에서D의 검색은 해당 주입된 클래스 이름(injected-class-name)을 찾습니다
한정된 이름은 항상
C
의 생성자를 지칭하는 것으로 간주됩니다. 이러한 이름은 생성자 선언에서만 사용될 수 있습니다(예: friend 생성자 선언, 생성자 템플릿 특수화, 생성자 템플릿 인스턴스화, 또는 생성자 정의)
또는 생성자를 상속하는 데 사용될 수 있습니다
(C++11부터)
.
struct A { A(); A(int); template<class T> A(T) {} }; using A_alias = A; A::A() {} A_alias::A(int) {} template A::A(double); struct B : A { using A_alias::A; }; A::A a; // 오류: A::A는 타입이 아닌 생성자로 간주됨 struct A::A a2; // OK, 'A a2;'와 동일 B::A b; // OK, 'A b;'와 동일
결함 보고서
다음의 동작 변경 결함 보고서들은 이전에 발표된 C++ 표준에 소급 적용되었습니다.
| DR | 적용 대상 | 게시된 동작 | 올바른 동작 |
|---|---|---|---|
| CWG 1004 | C++98 |
injected-class-name이 template template 인자가 될 수 없었음
|
허용되며, 이 경우 클래스 템플릿 자체를 참조함
|
| CWG 2637 | C++98 | 전체 template-id가 injected-class-name이 될 수 있었음 | 템플릿 이름만 가능함 |