Spec-Zone.ru › C++

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

Встроенное имя класса — это имя класса в пределах области действия этого класса, не содержащее квалификатор.

В шаблоне класса, встроенное имя класса может использоваться как имя шаблона, ссылающееся на текущий шаблон, или как имя класса, ссылающееся на текущую инстанциацию.

Объяснение

В области действия класса имя текущего класса рассматривается как имя публичного члена; это называется встроенным именем класса. Точка объявления имени находится сразу после открывающей фигурной скобки определения класса.

int X;
 
struct X
{
    void f()
    {
        X* p;   // OK. X refers to the injected-class-name
        ::X* q; // Error: name lookup finds a variable name, which hides the struct 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
};

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

Как и другие классы, шаблоны классов имеют встроенное имя класса. Встроенное имя класса может использоваться как имя шаблона или как имя типа.

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

  • за ним следует <
  • оно используется как аргумент шаблона шаблона
  • это последний идентификатор в полном спецификаторе класса объявления шаблона класса-друга.

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

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>
};

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

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
};

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

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

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

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
};

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

Конструкторы не имеют имён, но встроенное имя класса содержащего класса рассматривается как имя конструктора в объявлениях и определениях конструкторов.

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

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

квалифицированное имя всегда рассматривается как имя конструктора C. Такое имя может быть использовано только в объявлении конструктора (например, в объявлении конструктора-друга, специализации шаблона конструктора, инстанциации шаблона конструктора или определении конструктора) или для наследования конструкторов(с 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;'

Отчёты об ошибках

Следующие отчёты об ошибках, меняющие поведение, были применены ретроактивно к ранее опубликованным стандартам C++.

DR Применяется к Поведение, опубликованное в Правильное поведение
CWG 1004 C++98 встроенное имя класса не может
быть аргументом шаблона шаблона
разрешено, в этом случае оно относится к
самому шаблону класса

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/injected-class-name

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API