17 Templates [temp]

17.7 Template instantiation and specialization [temp.spec]

17.7.1 Implicit instantiation [temp.inst]

Если специализация шаблона класса не была explicitly instantiated или explicitly specialized, специализация шаблона класса неявно создается, когда на специализацию ссылаются в контексте, который требует полностью определенного типа объекта, или когда полнота типа класса влияет на семантику программы. [ Note: В частности, если семантика выражения зависит от списков членов или базовых классов специализации шаблона класса, специализация шаблона класса генерируется неявно. Например, удаление указателя на тип класса зависит от того, объявляет ли класс деструктор, а преобразование между указателями в тип класса зависит от отношения наследования между двумя задействованными классами. ] [end noteExample:

template<class T> class B { /* ... */ };
template<class T> class D : public B<T> { /* ... */ };

void f(void*);
void f(B<int>*);

void g(D<int>* p, D<char>* pp, D<double>* ppp) {
  f(p);             // instantiation of D<int> required: call f(B<int>*)
  B<char>* q = pp;  // instantiation of D<char> required: convert D<char>* to B<char>*
  delete ppp;       // instantiation of D<double> required
}

end example] Если шаблон класса был объявлен, но не определен, при point of instantiationсоздании экземпляра будет получен неполный тип класса ([basic.types]). [Example:

template<class T> class X;
X<char> ch;         // error: incomplete type X<char>

end example] [ Note: В объявлении шаблона local class перечисление или и члены локального класса никогда не считаются сущностями, которые могут быть созданы отдельно (это включает их аргументы по умолчанию noexcept-specifiers, и инициализаторы нестатических элементов данных, если таковые имеются). В результате выполняется поиск зависимых имен, проверяются семантические ограничения, и любые используемые шаблоны создаются как часть создания экземпляра объекта, в котором объявлен локальный класс или перечисление. ]end note

Неявное создание экземпляра специализации шаблона класса вызывает неявное создание экземпляров объявлений, но не определений, аргументов по умолчанию или noexcept-specifiers функций-членов класса, классов-членов, перечислений элементов с заданной областью действия, элементов статических данных, шаблонов элементов и других элементов; и это вызывает неявное создание экземпляров определений перечислений членов с незаданной областью и анонимных объединений членов. Однако для определения того, является ли созданное повторное объявление действительным в соответствии с [basic.def.odr] и [class.mem], объявление, которое соответствует определению в шаблоне, считается определением. [Example:

template<class T, class U>
struct Outer {
  template<class X, class Y> struct Inner;
  template<class Y> struct Inner<T, Y>;         // #1a
  template<class Y> struct Inner<T, Y> { };     // #1b; OK: valid redeclaration of #1a
  template<class Y> struct Inner<U, Y> { };     // #2
};

Outer<int, int> outer;                          // error at #2

Outer<int, int>​::​Inner<int, Y> повторно заявлен на # 1b. (Он не определен, но отмечен как связанный с определением в Outer<T, U>.) # 2 также является повторным объявлением # 1a. Он отмечен как связанный с определением, поэтому это недопустимое повторное объявление той же частичной специализации.

template<typename T> struct Friendly {
  template<typename U> friend int f(U) { return sizeof(T); }
};
Friendly<char> fc;
Friendly<float> ff;                             // ill-formed: produces second definition of f(U)

end example]

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

Если специализация шаблона функции не была явно создана или явно специализирована, специализация шаблона функции создается неявно, когда на специализацию ссылаются в контексте, который требует существования определения функции. Функция, объявление которой было создано из определения дружественной функции, создается неявно, когда на нее ссылаются в контексте, который требует существования определения функции. Если вызов не относится к явной специализации шаблона функции или к функции-члену явно специализированного шаблона класса, аргумент по умолчанию для шаблона функции или функция-член шаблона класса неявно создается, когда функция вызывается в контексте, который требует значение аргумента по умолчанию.

[Example:

template<class T> struct Z {
  void f();
  void g();
};

void h() {
  Z<int> a;         // instantiation of class Z<int> required
  Z<char>* p;       // instantiation of class Z<char> not required
  Z<double>* q;     // instantiation of class Z<double> not required

  a.f();            // instantiation of Z<int>​::​f() required
  p->g();           // instantiation of class Z<char> required, and
                    // instantiation of Z<char>​::​g() required
}

Ничто в этом примере не требуется class Z<double>, Z<int>​::​g()или Z<char>​::​f() неявный экземпляр. ]end example

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

Если функция, выбранная с помощью, overload resolution может быть определена без создания экземпляра определения шаблона класса, не указано, действительно ли это создание имеет место. [Example:

template <class T> struct S {
  operator int();
};

void f(int);
void f(S<int>&);
void f(S<float>);

void g(S<int>& sr) {
  f(sr);            // instantiation of S<int> allowed but not required
                    // instantiation of S<float> allowed but not required
};

end example]

Если шаблон функции или специализация шаблона функции-члена используется способом, который включает разрешение перегрузки, объявление специализации неявно создается ([temp.over]).

Реализация не должна неявно создавать экземпляр шаблона функции, шаблона переменной, шаблона члена, невиртуальной функции-члена, класса-члена, члена статических данных в шаблоне класса или подвыпуска constexpr if оператора, если только такое создание не требуется. . Не указано, создает ли реализация неявно виртуальную функцию-член шаблона класса, если в противном случае виртуальная функция-член не была бы создана. Использование специализации шаблона в аргументе по умолчанию не должно вызывать неявное создание экземпляра шаблона, за исключением того, что может быть создан экземпляр шаблона класса, где его полный тип необходим для определения правильности аргумента по умолчанию. Использование аргумента по умолчанию в вызове функции вызывает неявное создание экземпляров специализаций в аргументе по умолчанию.

Неявно созданные экземпляры специализации шаблонов классов, функций и переменных помещаются в пространство имен, в котором определен шаблон. Неявно созданные экземпляры специализаций для членов шаблона класса помещаются в пространство имен, где определен включающий шаблон класса. Неявно созданные экземпляры шаблонов членов помещаются в пространство имен, в котором определен включающий класс или шаблон класса. [Example:

namespace N {
  template<class T> class List {
  public:
    T* get();
  };
}

template<class K, class V> class Map {
public:
  N::List<V> lt;
  V get(K);
};

void g(Map<const char*,int>& m) {
  int i = m.get("Nicholas");
}

вызов lt.get() from Map<const char*,int>​::​get() будет помещаться List<int>​::​get() в пространство имен, N а не в глобальное пространство имен. ]end example

Если шаблон функции f вызывается способом, требующим использования аргумента по умолчанию, выполняется поиск зависимых имен, проверяются ограничения семантики, и создание экземпляра любого шаблона, используемого в аргументе по умолчанию, выполняется, как если бы аргумент по умолчанию имел был инициализатором, используемым в специализации шаблона функции с той же областью действия, теми же параметрами шаблона и тем же доступом, что и у шаблона функции, f используемого в этой точке, за исключением того, что область, в которой объявлен тип закрытия ([expr.prim.lambda.closure]) - и, следовательно, ее связанные пространства имен - остаются такими, как определено из контекста определения для аргумента по умолчанию. Этот анализ называется default argument instantiation. Созданный аргумент по умолчанию затем используется как аргумент f.

Каждый аргумент по умолчанию создается независимо. [Example:

template<class T> void f(T x, T y = ydef(T()), T z = zdef(T()));

class  A { };

A zdef(A);

void g(A a, A b, A c) {
  f(a, b, c);       // no default argument instantiation
  f(a, b);          // default argument z = zdef(T()) instantiated
  f(a);             // ill-formed; ydef is not declared
}

end example]

Специализация noexcept-specifierшаблона функции не создается вместе с объявлением функции; он создается при необходимости ([except.spec]). Если такой объект noexcept-specifierнеобходим, но еще не создан, выполняется поиск зависимых имен, проверяются ограничения семантики, и создание экземпляра любого шаблона, используемого в, noexcept-specifierвыполняется так, как если бы оно было выполнено как часть создания экземпляра объявления объекта. специализация на этом этапе.

[ Note: [temp.point] определяет точку реализации специализации шаблона. ]end note

Существует количество, определяемое реализацией, которое указывает предел общей глубины рекурсивных экземпляров ([implimits]), которые могут включать более одного шаблона. Результат бесконечной рекурсии при создании экземпляра не определен. [Example:

template<class T> class X {
  X<T>* p;          // OK
  X<T*> a;          // implicit generation of X<T> requires
                    // the implicit instantiation of X<T*> which requires
                    // the implicit instantiation of X<T**> which …
};

end example]