Namespaces
Variants

Injected-class-name

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

주입된 클래스 이름은 해당 클래스 범위 내에서 클래스의 비한정 이름입니다.

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<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이 될 수 있었음 템플릿 이름만 가능함