17 Templates [temp]

17.6 Name resolution [temp.res]

17.6.2 Dependent names [temp.dep]

Внутри шаблона некоторые конструкции имеют семантику, которая может отличаться от одного экземпляра к другому. Такая конструкция зависит от параметров шаблона. В частности, типы и выражения могут зависеть от типа и / или значения параметров шаблона (как определено аргументами шаблона), и это определяет контекст для поиска имени для определенных имен. Выражения могут быть type-dependent (то есть его тип может зависеть от параметра шаблона) или value-dependent (то есть его значение при оценке как постоянное выражение ([expr.const]) может зависеть от параметра шаблона), как описано в этом подпункте. В выражении формы:

postfix-expression ( expression-listopt )

где postfix-expression является an unqualified-id, unqualified-id обозначает a, dependent name если

Если операнд оператора является выражением, зависящим от типа, оператор также обозначает зависимое имя. Такие имена не связаны и просматриваются в точке создания экземпляра шаблона ([temp.point]) как в контексте определения шаблона, так и в контексте точки создания экземпляра.

[Example:

template<class T> struct X : B<T> {
  typename T::A* pa;
  void f(B<T>* pb) {
    static int i = B<T>::i;
    pb->j++;
  }
};

имя базового класса, имя B<T>типа T​::​A, имена B<T>​::​i и pb->j явно зависят от template-parameter. ]end example

В определении класса или шаблона класса область видимостиdependent base class не проверяется во время неквалифицированного поиска имени ни в точке определения шаблона или члена класса, ни во время создания экземпляра шаблона или члена класса. [Example:

typedef double A;
template<class T> class B {
  typedef int A;
};
template<class T> struct X : B<T> {
  A a;              // a has type double
};

Имя типа A в определении X<T> связывается с именем typedef, определенным в области глобального пространства имен, а не с именем typedef, определенным в базовом классе B<T>. ] [end exampleExample:

struct A {
  struct B { /* ... */ };
  int a;
  int Y;
};

int a;

template<class T> struct Y : T {
  struct B { /* ... */ };
  B b;                          // The B defined in Y
  void f(int i) { a = i; }      // ​::​a
  Y* p;                         // Y<T>
};

Y<A> ya;

Члены A​::​B, A​::​aи A​::​Y аргумента шаблона A не влияют на привязку имен в Y<A>. ]end example

17.6.2.1 Dependent types [temp.dep.type]

Имя относится к тому, current instantiation если это

  • в определении шаблона класса, вложенного класса шаблона класса, члена шаблона класса или члена вложенного класса шаблонаinjected-class-name класса, шаблона класса или вложенного класса,

  • в определении шаблона первичного класса или члена шаблона первичного класса, имя шаблона класса, за которым следует список аргументов шаблона первичного шаблона (как описано ниже), заключенный в <> (или эквивалентную специализацию псевдонима шаблона),

  • в определении вложенного класса шаблона класса имя вложенного класса, на который ссылается как на член текущего экземпляра, или

  • в определении частичной специализации или члена частичной специализации - имя шаблона класса, за которым следует список аргументов шаблона частичной специализации, заключенной в <> (или эквивалентная специализация псевдонима шаблона). Если параметрnth шаблона является пакетом параметров,nаргумент шаблона th является pack expansion шаблоном, шаблон которого является именем пакета параметров.

Список аргументов шаблона первичного шаблона - это список аргументов шаблона, в котором nаргумент th шаблона имеет значение параметра nth шаблона шаблона класса. Еслиnth параметром шаблона является a template parameter pack,nаргумент th шаблона - это a pack expansion , шаблон которого является именем пакета параметров шаблона.

Аргумент шаблона, который эквивалентен параметру шаблона (т. Е. Имеет то же постоянное значение или тот же тип, что и параметр шаблона), может использоваться вместо этого параметра шаблона в ссылке на текущий экземпляр. В случае аргумента шаблона, не являющегося типом, аргументу должно быть задано значение параметра шаблона, а не выражение, в котором параметр шаблона появляется как часть выражения. [Example:

template <class T> class A {
  A* p1;                        // A is the current instantiation
  A<T>* p2;                     // A<T> is the current instantiation
  A<T*> p3;                     // A<T*> is not the current instantiation
  ::A<T>* p4;                   // ​::​A<T> is the current instantiation
  class B {
    B* p1;                      // B is the current instantiation
    A<T>::B* p2;                // A<T>​::​B is the current instantiation
    typename A<T*>::B* p3;      // A<T*>​::​B is not the current instantiation
  };
};

template <class T> class A<T*> {
  A<T*>* p1;                    // A<T*> is the current instantiation
  A<T>* p2;                     // A<T> is not the current instantiation
};

template <class T1, class T2, int I> struct B {
  B<T1, T2, I>* b1;             // refers to the current instantiation
  B<T2, T1, I>* b2;             // not the current instantiation
  typedef T1 my_T1;
  static const int my_I = I;
  static const int my_I2 = I+0;
  static const int my_I3 = my_I;
  B<my_T1, T2, my_I>* b3;       // refers to the current instantiation
  B<my_T1, T2, my_I2>* b4;      // not the current instantiation
  B<my_T1, T2, my_I3>* b5;      // refers to the current instantiation
};

end example]

Adependent base class - это базовый класс, который является зависимым типом и не является текущим экземпляром. [ Note: Базовый класс может быть текущим экземпляром в случае, если вложенный класс называет включающий класс базовым. [Example:

template<class T> struct A {
  typedef int M;
  struct B {
    typedef void M;
    struct C;
  };
};

template<class T> struct A<T>::B::C : A<T> {
  M m;                          // OK, A<T>​::​M
};

end example] ]end note

Имя - это member of the current instantiation если это

  • Неквалифицированное имя, которое при поиске относится по крайней мере к одному члену класса, который является текущим экземпляром или его независимым базовым классом. [ Note: Это может произойти только при поиске имени в области, содержащейся в определении шаблона класса. ] end note

  • A, qualified-id в котором nested-name-specifier относится к текущему экземпляру и который при поиске относится по крайней мере к одному члену класса, который является текущим экземпляром, или его независимым базовым классом. [ Note: Если такой член не найден, а у текущего экземпляра есть какие-либо зависимые базовые классы, то qualified-idэто член неизвестной специализации; см. ниже. ]end note

  • id-expressionОбозначая член вclass member access выражении для которого тип выражения объекта является текущим конкретизации, и id-expression, когдаlooked up, относится к по меньшей мере , одного члена класса , который является текущим конкретизации или не зависящих от их базового класса. [ Note: Если такой член не найден, а у текущего экземпляра есть какие-либо зависимые базовые классы, то id-expressionэто член неизвестной специализации; см. ниже. ] end note

[Example:

template <class T> class A {
  static const int i = 5;
  int n1[i];                    // i refers to a member of the current instantiation
  int n2[A::i];                 // A​::​i refers to a member of the current instantiation
  int n3[A<T>::i];              // A<T>​::​i refers to a member of the current instantiation
  int f();
};

template <class T> int A<T>::f() {
  return i;                     // i refers to a member of the current instantiation
}

end example]

Имя - это,dependent member of the current instantiation если он является членом текущего экземпляра, который при поиске ссылается по крайней мере на один член класса, который является текущим экземпляром.

Имя - это member of an unknown specialization если это

  • Объект, qualified-id в котором nested-name-specifier именуется зависимый тип, не являющийся текущим экземпляром.

  • A, qualified-idв котором nested-name-specifier относится к текущему экземпляру, текущий экземпляр имеет по крайней мере один зависимый базовый класс, а поиск имени qualified-idне находит ни одного члена класса, который является текущим экземпляром или его независимым базовым классом.

  • id-expressionОбозначая член в class member access выражении , в котором либо

    • тип объектного выражения - это текущая реализация, текущая реализация имеет по крайней мере один зависимый базовый класс, а поиск имени id-expressionне находит члена класса, который является текущим экземпляром, или его независимого базового класса; или

    • тип объектного выражения является зависимым и не является текущим экземпляром.

Если a, qualified-idв котором nested-name-specifier относится к текущему экземпляру, не является членом текущего экземпляра или элементом неизвестной специализации, программа имеет неправильный формат, даже если шаблон, содержащий элемент, не создается qualified-id; диагностика не требуется. Точно так же, если id-expressionвыражение доступа к члену класса, для которого тип выражения объекта является текущим экземпляром, не относится к члену текущего экземпляра или члену неизвестной специализации, программа имеет неправильный формат, даже если шаблон содержащее выражение доступа к члену не создается; диагностика не требуется. [Example:

template<class T> class A {
  typedef int type;
  void f() {
    A<T>::type i;               // OK: refers to a member of the current instantiation
    typename A<T>::other j;     // error: neither a member of the current instantiation nor
                                // a member of an unknown specialization
  }
};

end example]

Если для заданного набора аргументов шаблона создается экземпляр специализации шаблона, который ссылается на член текущего экземпляра с qualified-idвыражением доступа к члену класса or, имя в qualified-idвыражении доступа к члену класса or ищется в экземпляре шаблона. контекст. Если результат этого поиска отличается от результата поиска имени в контексте определения шаблона, поиск имени неоднозначен. [Example:

struct A {
  int m;
};

struct B {
  int m;
};

template<typename T>
struct C : A, T {
  int f() { return this->m; }   // finds A​::​m in the template definition context
  int g() { return m; }         // finds A​::​m in the template definition context
};

template int C<B>::f();     // error: finds both A​::​m and B​::​m
template int C<B>::g();     // OK: transformation to class member access syntax
                            // does not occur in the template definition context; see [class.mfct.non-static]

end example]

Тип является зависимым, если он

  • параметр шаблона,

  • сотрудник неизвестной специализации,

  • вложенный класс или перечисление, которое является зависимым членом текущего экземпляра,

  • тип cv-qualified, где cv-unqualified тип является зависимым,

  • составной тип, созданный из любого зависимого типа,

  • тип массива, тип элемента которого является зависимым или чья граница (если есть) зависит от значения,

  • тип функции, спецификация исключения которой зависит от значения,

  • a, simple-template-id в котором либо имя шаблона является параметром шаблона, либо любой из аргументов шаблона является зависимым типом или выражением, которое зависит от типа или значения, или является расширением пакета [ Note: Сюда входитinjected-class-name шаблон класса, используемый без расширения template-argument-list. ] , или end note

  • обозначается , где есть . decltype(expression)expressiontype-dependent

[ Note: Поскольку typedef не вводит новые типы, а вместо этого просто ссылается на другие типы, имя, которое ссылается на typedef, который является членом текущего экземпляра, зависит только в том случае, если тип, на который ссылается, является зависимым. ]end note

17.6.2.2 Type-dependent expressions [temp.dep.expr]

За исключением случаев, описанных ниже, выражение зависит от типа, если какое-либо подвыражение зависит от типа.

this зависит от типа, если тип класса включающей функции-члена зависит ([temp.dep.type]).

Зависит от id-expression типа, если он содержит

  • identifier , связанный с именем поиска с одним или более деклараций объявлен с зависимым типом,

  • identifier , связанный с именем поиска с не-типа template-parameter объявлена с типом , который содержитplaceholder type,

  • identifier, связанный с именем поиска с одним или более деклараций функций членов текущего экземпляра объявленных с типом возвращаемого , который содержит тип заполнителя,

  • identifier, связанный с именем поиском сstructured binding declaration которого brace-or-equal-initializerявляется типом-зависимым,

  • identifier _­_­func_­_­, где любая вмещающих функция представляет собой шаблон, член шаблона класса, или общая лямбду,

  • template-id , что зависит,

  • a, conversion-function-id который указывает зависимый тип, или

  • a nested-name-specifier или a, в qualified-id котором упоминается член неизвестной специализации;

или если он называет зависимый член текущего экземпляра, который является статическим элементом данных типа «массив неизвестных границT» для someT ([temp.static]). Выражения следующих форм зависят от типа, только если тип, указанный с помощью type-id, simple-type-specifier или new-type-id является зависимым, даже если любое подвыражение зависит от типа:

simple-type-specifier ( expression-listopt )
::opt new new-placementopt new-type-id new-initializeropt
::opt new new-placementopt ( type-id ) new-initializeropt
dynamic_cast < type-id > ( expression )
static_cast < type-id > ( expression )
const_cast < type-id > ( expression )
reinterpret_cast < type-id > ( expression )
( type-id ) cast-expression

Выражения следующих форм никогда не зависят от типа (поскольку тип выражения не может быть зависимым):

literal
postfix-expression . pseudo-destructor-name
postfix-expression -> pseudo-destructor-name
sizeof unary-expression
sizeof ( type-id )
sizeof ... ( identifier )
alignof ( type-id )
typeid ( expression )
typeid ( type-id )
::opt delete cast-expression
::opt delete [ ] cast-expression
throw assignment-expressionopt
noexcept ( expression )

[ Note: Для стандартного библиотечного макросаoffsetofсм[support.types].. ]end note

Aclass member access expression зависит от типа, если выражение относится к члену текущего экземпляра, а тип указанного члена является зависимым, или если выражение доступа к члену класса относится к члену неизвестной специализации. [ Note: В выражении формы x.y или xp->y типа выражения обычно является тип члена y класса x (или класса, на который указывает xp). Однако, если x или xp относится к зависимому типу, который не является текущим экземпляром, тип y всегда является зависимым. Если x илиxp относится к независимому типу или относится к текущему экземпляру, тип y является типом выражения доступа к члену класса. ]end note

A braced-init-listзависит от типа, если какой-либо элемент зависит от типа или является расширением пакета.

A fold-expressionзависит от типа.

17.6.2.3 Value-dependent expressions [temp.dep.constexpr]

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

An id-expression зависит от значения, если:

  • это зависит от типа,

  • это имя параметра шаблона, не являющегося типом,

  • он называет статический член данных, который является зависимым членом текущего экземпляра и не инициализируется в a member-declarator,

  • он называет статическую функцию-член, которая является зависимым членом текущего экземпляра, или

  • это константа литерального типа и инициализируется выражением, зависящим от значения.

Выражения следующей формы зависят от значения, если unary-expressionили expression зависит от типа, или type-id зависит:

sizeof unary-expression
sizeof ( type-id )
typeid ( expression )
typeid ( type-id )
alignof ( type-id )
noexcept ( expression )

[ Note: Для стандартного библиотечного макросаoffsetofсм[support.types].. ]end note

Выражения следующей формы являются значением-зависимой , если либо type-id или simple-type-specifier зависит , или , expression или cast-expression является значением в зависимости от:

simple-type-specifier ( expression-listopt )
static_cast < type-id > ( expression )
const_cast < type-id > ( expression )
reinterpret_cast < type-id > ( expression )
( type-id ) cast-expression

Выражения следующей формы зависят от значения:

sizeof ... ( identifier )
fold-expression

Выражение формы, в которой имена зависимых членов текущего экземпляра зависят от значения. Выражение вида также является значением-зависимым , если оценивать как успешно , и результат оценки относится к шаблонному объекту , который является объектом с длительностью статической или потоком хранения или функцией - члена.&qualified-idqualified-id&cast-expressioncast-expressioncore constant expression

17.6.2.4 Dependent template arguments [temp.dep.temp]

Тип template-argument является зависимым, если тип, который он указывает, является зависимым.

Не-тип template-argument является зависимым, если его тип является зависимым или константное выражение, которое он задает, зависит от значения.

Кроме того, не-тип template-argument является зависимым, если соответствующий не-тип template-parameter относится к типу ссылки или указателя, а template-argument обозначает или указывает на член текущего экземпляра или член зависимого типа.

Шаблон template-argument является зависимым, если он называет template-parameter или qualified-id относится к члену неизвестной специализации.