Spec-Zone.ru › C++

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

Внедрённое имя класса — это неквалифицированное имя класса в области видимости этого класса.

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

Пояснение

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

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

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

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 внедрённое имя класса не могло
быть аргументом шаблона-шаблона
разрешено; в этом случае оно относится к самому
шаблону класса
CWG 2637 C++98 весь идентификатор шаблона мог быть внедрённым именем класса может быть только имя шаблона

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

Spec-Zone.ru

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