Специализация шаблона класса, функции, переменной или члена может быть явно создана из его шаблона. Функция-член, класс-член или статический член-данные шаблона класса могут быть явно созданы из определения члена, связанного с его шаблоном класса. Явное создание экземпляра шаблона функции или функции-члена шаблона класса не должно использовать спецификаторы 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 note qualified-idsimple-template-idunqualified-idtemplate-id[namespace.def] Note: [dcl.meaning] — end note Example:
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