17 Templates [temp]

17.7 Template instantiation and specialization [temp.spec]

17.7.2 Explicit instantiation [temp.explicit]

Специализация шаблона класса, функции, переменной или члена может быть явно создана из его шаблона. Функция-член, класс-член или статический член-данные шаблона класса могут быть явно созданы из определения члена, связанного с его шаблоном класса. Явное создание экземпляра шаблона функции или функции-члена шаблона класса не должно использовать спецификаторы inline или constexpr .

Синтаксис явного создания экземпляра:

explicit-instantiation:
	externopt template declaration

Есть две формы явного создания экземпляра: явное определение экземпляра и явное объявление экземпляра. Явное объявление экземпляра начинается с extern ключевого слова.

Если явная Инстанциация для класса или члена класса, elaborated-type-specifierв declarationдолжны включать в себя simple-template-id. Если явная Инстанциация для функции или члена функции, то unqualified-id в declaration должна быть либо template-id или, когда все аргументы шаблона может быть выведены, template-nameили operator-function-id. [ Note: Декларация может объявить qualified-id, в этом случае unqualified-id из qualified-id должно быть template-id. ] Если явное создание экземпляра предназначено для функции-члена, класса-члена или статического члена данных специализации шаблона класса, имя специализации шаблона класса в для имени члена должно быть . Если явное создание экземпляра предназначено для переменной, в объявлении должен быть . Явное создание экземпляра должно появиться во включающем пространстве имен своего шаблона. Если имя, объявленное в явном создании экземпляра, является неквалифицированным именем, явное создание экземпляра должно появиться в пространстве имен, в котором объявлен его шаблон, или, если это пространство имен является inline ( ), в любом пространстве имен из включающего его набора пространств имен. [ Относительно полных имен в деклараторах см . ] [end notequalified-idsimple-template-idunqualified-idtemplate-id[namespace.def]Note: [dcl.meaning]end noteExample:

template<class T> class Array { void mf(); };
template class Array<char>;
template void Array<int>::mf();

template<class T> void sort(Array<T>& v) { /* ... */ }
template void sort(Array<char>&);       // argument is deduced here

namespace N {
  template<class T> void f(T&) { }
}
template void N::f<int>(int&);

end example]

Объявление шаблона функции, шаблона переменной, функции-члена или статического члена данных шаблона класса или шаблона функции-члена класса или шаблона класса должно предшествовать явному созданию экземпляра этой сущности. Определение шаблона класса, класса-члена шаблона класса или шаблона класса-члена шаблона класса или класса должно предшествовать явному созданию экземпляра этой сущности, если только явному созданию экземпляра не предшествует явная специализация сущности с тем же аргументы шаблона. Если declaration явное создание именует неявно объявленное special member function, программа имеет неправильный формат .

Для заданного набора аргументов шаблона, если явное создание экземпляра шаблона появляется после объявления явной специализации для этого шаблона, явное создание экземпляра не имеет никакого эффекта. В противном случае для явного определения экземпляра определение шаблона функции, шаблона переменной, шаблона функции-члена или функции-члена или статического члена данных шаблона класса должно присутствовать в каждой единице перевода, в которой он явно создан.

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

namespace N {
  template<class T> class Y { void mf() { } };
}

template class Y<int>;          // error: class template Y not visible in the global namespace

using N::Y;
template class Y<int>;          // error: explicit instantiation outside of the namespace of the template

template class N::Y<char*>;             // OK: explicit instantiation in namespace N
template void N::Y<double>::mf();       // OK: explicit instantiation in namespace N

end example]

Конечный конец template-argument можно оставить неопределенным при явном создании экземпляра специализации шаблона функции или специализации шаблона функции-члена при условии, что он может быть выведен из типа параметра функции ([temp.deduct]). [Example:

template<class T> class Array { /* ... */ };
template<class T> void sort(Array<T>& v) { /* ... */ }

// instantiate sort(Array<int>&) – template-argument deduced
template void sort<>(Array<int>&);

end example]

Явное создание экземпляра, которое именует специализацию шаблона класса, также является явным экземпляром того же типа (объявление или определение) каждого из его членов (не включая элементы, унаследованные от базовых классов, и элементы, которые являются шаблонами), который ранее не был явно специализирован в единица трансляции, содержащая явное создание экземпляра, за исключением случаев, описанных ниже. [ Note: Кроме того, это обычно будет явным экземпляром определенных данных о классе, зависящих от реализации. ] end note

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

За исключением встроенных функций и переменных, объявления с типами, выведенными из их инициализатора или возвращаемого значения ([dcl.spec.auto]), const переменных литеральных типов, переменных ссылочных типов и специализаций шаблонов классов, явные объявления создания экземпляров имеют эффект подавления неявного создания экземпляра объекта для на которые они ссылаются. [ Note: Намерение состоит в том, чтобы встроенная функция, являющаяся предметом явного объявления экземпляра, по-прежнему odr-used создавалась неявно, когда так, чтобы тело можно было рассматривать для встраивания, но чтобы внешняя копия встроенной функции не создавалась в единица перевода. ]end note

Если объект является предметом как явного объявления создания экземпляра, так и явного определения экземпляра в одной и той же единице преобразования, определение должно следовать за объявлением. Сущность, которая является предметом явного объявления экземпляра и который также используется таким образом, который в противном случае вызвал бы implicit instantiation в блоке преобразования, должен быть предметом явного определения экземпляра где-то в программе; в противном случае программа имеет неправильный формат, и диагностика не требуется. [ Note: Это правило применяется к встроенным функциям, даже если явное объявление экземпляра такой сущности не имеет другого нормативного эффекта. Это необходимо для того, чтобы гарантировать, что если адрес встроенной функции будет взят в блоке трансляции, в котором реализация решила подавить внешнее тело, другая единица трансляции предоставит тело. ] Явное объявление экземпляра не должно называть специализацию шаблона с внутренней связью.end note

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

Явное создание экземпляра не означает использование аргумента по умолчанию, поэтому создание экземпляра аргумента по умолчанию не выполняется. [Example:

char* p = 0;
template<class T> T g(T x = &p) { return x; }
template int g<int>(int);       // OK even though &p isn't an int.

end example]