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 может использоваться либо как имя шаблона, ссылающееся на текущий шаблон, либо как имя класса, ссылающееся на текущую инстанциацию.

Содержание

Объяснение

В области класса имя текущего класса или имя шаблона текущего шаблона класса рассматривается как если бы оно было именем публичного члена; это называется 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-names наследуются. При наличии private или protected наследования injected-class-name косвенного базового класса может оказаться недоступным в производном классе.

struct A {};
struct B : private A {};
struct C : public B
{
    A* p;   // Ошибка: injected-class-name A недоступен
    ::A* q; // OK, не использует injected-class-name
{;

В шаблоне класса

Внедренное имя класса шаблона класса может использоваться как имя шаблона или имя типа.

В следующих случаях injected-class-name рассматривается как template-name самого шаблона класса:

В противном случае оно трактуется как имя типа и эквивалентно имени шаблона, за которым следуют параметры шаблона класса, заключённые в <> .

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 specialization или partial specialization , когда внедренное имя класса используется как имя типа, оно эквивалентно имени шаблона, за которым следуют аргументы шаблона специализации или частичной специализации шаблона класса, заключенные в <> .

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, может использоваться для именования другой специализации
};

Внедренное-имя-класса шаблона класса или специализации шаблона класса может использоваться либо как имя-шаблона, либо как имя-типа везде, где оно находится в области видимости.

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: аргумент по умолчанию использует injected-class-name как шаблон

Поиск, который находит внедренное имя класса, может привести к неоднозначности в определенных случаях (например, если оно найдено в более чем одном базовом классе). Если все найденные внедренные имена классов ссылаются на специализации одного и того же шаблона класса, и если имя используется как имя шаблона, ссылка относится к самому шаблону класса, а не к его специализации, и не является неоднозначной.

template<class T>
struct Base {};
template<class T>
struct Derived: Base<int>, Base<char>
{
    typename Derived::Base b;         // ошибка: неоднозначность
    typename Derived::Base<double> d; // OK
};

Внедренное имя класса и конструкторы

Конструкторы не имеют имён, но внедрённое-имя-класса (injected-class-name) охватывающего класса считается именем конструктора в объявлениях и определениях конструкторов.

В квалифицированном имени C::D , если

  • поиск по имени не игнорирует имена функций, и
  • поиск D в области видимости класса C находит его injected-class-name

квалифицированное имя всегда считается именующим конструктор C . Такое имя может использоваться только в объявлении конструктора (например, в объявлении friend-конструктора, специализации шаблона конструктора, инстанциации шаблона конструктора или определении конструктора) или для наследования конструкторов (since 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 argument
разрешено, в этом случае он ссылается на сам
class template
CWG 2637 C++98 весь template-id мог быть injected-class-name только template name может