17 Templates [temp]

17.6 Name resolution [temp.res]

17.6.1 Locally declared names [temp.local]

Как и обычные (не шаблонные) классы, шаблоны классов имеют расширение injected-class-name. Введенное-имя-класса может использоваться как template-nameили type-name. Когда он используется с template-argument-list, как template-argumentдля шаблона template-parameterили как окончательный идентификатор в elaborated-type-specifierобъявлении шаблона дружественного класса, он ссылается на сам шаблон класса. В противном случае, это равносильно тому , template-name сопровождаемое template-parameters шаблон класса , заключенном в <>.

В рамках специализации шаблона класса или частичной специализации, когда имя injected-class-name используется как a type-name, оно эквивалентно, за template-nameкоторым следует template-arguments специализация шаблона класса или частичная специализация, заключенная в <>. [Example:

template<template<class> class T> class A { };
template<class T> class Y;
template<> class Y<int> {
  Y* p;                               // meaning Y<int>
  Y<char>* q;                         // meaning Y<char>
  A<Y>* a;                            // meaning A<​::​Y>
  class B {
    template<class> friend class Y;   // meaning ​::​Y
  };
};

end example]

Нагнетаемого класса имя шаблона класса или класса специализации шаблона может быть использован либо как template-nameили type-name там , где она находится в области видимости. [Example:

template <class T> struct Base {
  Base* p;
};

template <class T> struct Derived: public Base<T> {
  typename Derived::Base* p;    // meaning Derived​::​Base<T>
};

template<class T, template<class> class U = T::template Base> struct Third { };
Third<Base<int> > t;            // OK: default argument uses injected-class-name as a template

end example]

Поиск, который находит внедренное имя-класса ([class.member.lookup]), в некоторых случаях может привести к неоднозначности (например, если он найден более чем в одном базовом классе). Если все найденные имена внедренных классов относятся к специализациям одного и того же шаблона класса, и если имя используется как a template-name, ссылка относится к самому шаблону класса, а не к его специализации, и не является двусмысленной. [Example:

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

end example]

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

template<class T> class X {
  X* p;             // meaning X<T>
  X<T>* p2;
  X<int>* p3;
  ::X* p4;          // error: missing template argument list
                    // ​::​X does not refer to the injected-class-name
};

end example]

A template-parameter не следует повторно объявлять в пределах своей области действия (включая вложенные области действия). Имя A template-parameter не должно совпадать с именем шаблона. [Example:

template<class T, int i> class Y {
  int T;            // error: template-parameter redeclared
  void f() {
    char T;         // error: template-parameter redeclared
  }
};

template<class X> class X;      // error: template-parameter redeclared

end example]

В определении члена шаблона класса, который появляется вне определения шаблона класса, имя члена шаблона класса скрывает имя template-parameter любого включающего шаблона класса (но не template-parameterчлена, если член является шаблон класса или функции). [Example:

template<class T> struct A {
  struct B { /* ... */ };
  typedef void C;
  void f();
  template<class U> void g(U);
};

template<class B> void A<B>::f() {
  B b;              // A's B, not the template parameter
}

template<class B> template<class C> void A<B>::g(C) {
  B b;              // A's B, not the template parameter
  C c;              // the template parameter C, not A's C
}

end example]

В определении члена шаблона класса, который появляется за пределами пространства имен, содержащего определение шаблона класса, имя template-parameter скрывает имя члена этого пространства имен. [Example:

namespace N {
  class C { };
  template<class T> class B {
    void f(T);
  };
}
template<class C> void N::B<C>::f(C) {
  C b;              // C is the template parameter, not N​::​C
}

end example]

В определении шаблона класса или в определении члена такого шаблона, который появляется вне определения шаблона, для каждого независимого базового класса ([temp.dep.type]), если имя базового класса или имя члена базовый класс такой же , как название template-parameter, имя базового класса или члена имя hides на template-parameter имя. [Example:

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

template<class B, class a> struct X : A {
  B b;              // A's B
  a b;              // error: A's a isn't a type name
};

end example]