Injected-class-name
Injected-class-name (주입된 클래스 이름)
injected-class-name 은 어떤 클래스의 범위 안에서 그 클래스 자체를 가리키는 비한정 이름(unqualified name)이에요.
클래스 템플릿 안에서는 injected-class-name 을 두 가지로 쓸 수 있어요. 현재 템플릿을 가리키는 템플릿 이름으로 쓰거나, 현재 인스턴스화(current instantiation)를 가리키는 클래스 이름으로 쓸 수 있죠.
출처: cppreference
참고: cppreference 의 원래 페이지 주소는
https://en.cppreference.com/w/cpp/language/injected-class-name이에요.
본문
설명 (Explanation)
클래스 범위 안에서, 현재 클래스의 클래스 이름 또는 현재 클래스 템플릿의 템플릿 이름은 마치 public 멤버 이름 인 것처럼 취급돼요. 이걸 injected-class-name 이라고 불러요. 이 이름의 선언 지점(point of declaration)은 클래스(템플릿) 정의의 여는 중괄호 바로 뒤예요.
int X;
struct X
{
void f()
{
X* p; // OK, X is an injected-class-name
::X* q; // Error: name lookup finds a variable name, which hides the struct name
}
};
template<class T>
struct Y
{
void g()
{
Y* p; // OK, Y is an injected-class-name
Y<T>* q; // OK, Y is an injected-class-name, but Y<T> is not
}
};
다른 멤버들처럼 injected-class-name 도 상속돼요. private 또는 protected 상속이 있으면, 간접 기반 클래스의 injected-class-name 이 파생 클래스에서 접근 불가능하게 끝날 수 있어요.
struct A {};
struct B : private A {};
struct C : public B
{
A* p; // Error: injected-class-name A is inaccessible
::A* q; // OK, does not use the injected-class-name
};
클래스 템플릿 안에서 (In class template)
클래스 템플릿의 injected-class-name 은 템플릿 이름(template-name)이나 타입 이름(type-name)으로 쓸 수 있어요.
다음 경우에 injected-class-name 은 클래스 템플릿 자체의 템플릿 이름 으로 취급돼요.
<가 바로 뒤에 올 때- 템플릿 템플릿 인자(template template argument)로 쓰일 때
- friend 클래스 템플릿 선언의 정교화된 클래스 지정자(elaborated class specifier)의 마지막 식별자일 때
그 외에는 타입 이름 으로 취급되고, 템플릿 이름 뒤에 클래스 템플릿의 템플릿 매개변수들을 <>로 감싼 것과 동등해요.
template<template<class, class> class>
struct A;
template<class T1, class T2>
struct X
{
X<T1, T2>* p; // OK, X is treated as a template-name
using a = A<X>; // OK, X is treated as a template-name
template<class U1, class U2>
friend class X; // OK, X is treated as a template-name
X* q; // OK, X is treated as a type-name, equivalent to X<T1, T2>
};
클래스 템플릿 특수화 또는 부분 특수화의 범위 안에서, injected-class-name 을 타입 이름으로 쓰면 그 특수화 또는 부분 특수화의 템플릿 인자들을 <>로 감싼 템플릿 이름과 동등해요.
template<>
struct X<void, void>
{
X* p; // OK, X is treated as a type-name, equivalent to X<void, void>
template<class, class>
friend class X; // OK, X is treated as a template-name (same as in primary template)
X<void, void>* q; // OK, X is treated as a template-name
};
template<class T>
struct X<char, T>
{
X* p, q; // OK, X is treated as a type-name, equivalent to X<char, T>
using r = X<int, int>; // OK, can be used to name another specialization
};
클래스 템플릿 또는 클래스 템플릿 특수화의 injected-class-name 은 범위 안에 있는 어디서든 템플릿 이름이나 타입 이름으로 쓸 수 있어요.
template<>
class X<int, char>
{
class B
{
X a; // meaning X<int, char>
template<class, class>
friend class X; // meaning ::X
};
};
template<class T>
struct Base
{
Base* p; // OK: Base means Base<T>
};
template<class T>
struct Derived : public Base<T*>
{
typename Derived::Base* p; // OK: Derived::Base means Derived<T>::Base,
// which is Base<T*>
};
template<class T, template<class> class U = T::template Base>
struct Third {};
Third<Derived<int>> t; // OK: default argument uses injected-class-name as a template
injected-class-name 을 찾아내는 룩업은 특정 경우(예: 둘 이상의 기반 클래스에서 발견될 때) 모호성을 낳을 수 있어요. 발견된 injected-class-name 들이 모두 같은 클래스 템플릿의 특수화를 가리키고, 이름을 템플릿 이름으로 쓴다면, 그 참조는 특수화가 아니라 클래스 템플릿 자체를 가리키며 모호하지 않아요.
template<class T>
struct Base {};
template<class T>
struct Derived: Base<int>, Base<char>
{
typename Derived::Base b; // error: ambiguous
typename Derived::Base<double> d; // OK
};
injected-class-name 과 생성자 (injected-class-name and constructors)
생성자는 이름이 없지만, 둘러싼 클래스의 injected-class-name 은 생성자 선언과 정의에서 생성자를 가리키는 것으로 간주돼요.
한정 이름 C::D에서
- 이름 룩업이 함수 이름을 무시하지 않고,
- 클래스
C의 범위 안에서D룩업이C의 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; // Error: A::A is considered to name a constructor, not a type
struct A::A a2; // OK, same as 'A a2;'
B::A b; // OK, same as 'A b;'
결함 보고 (Defect reports)
동작 변경 결함 보고로 주요하게 조정된 내용은 이래요. injected-class-name 이 템플릿 템플릿 인자가 될 수 있게 되고 그 경우 클래스 템플릿 자신을 가리키게 됨(CWG 1004), 전체 template-id 가 아니라 템플릿 이름만 injected-class-name 이 될 수 있게 됨(CWG 2637) 등이에요.