Подтвердить что ты не робот

Когда вы будете использовать шаблонный экземпляр шаблона?

Я только что читал о явном экземпляре шаблона:

template struct MyStruct<long>;

Он был описан как "довольно редкий", поэтому при каких обстоятельствах это было бы полезно?

4b9b3361

Ответ 1

Один из вариантов использования - скрыть определения от конечного пользователя.

tpl.h

template<typename T>
void func(); // Declaration

tpl.cpp

template<typename T>
void func()
{
    // Definition
}

template void func<int>(); // explicit instantiation for int
template void func<double>();  // explicit instantiation for double

main.cpp

#include "tpl.h"
int main()
{
    func<double>(); // OK
    func<int>(); // OK
    // func<char>(); - Linking ERROR
}

Ответ 2

Явное создание экземпляров предназначено для оптимизации использования библиотек шаблонов, предоставляющих некоторые (в основном используемые) экземпляры шаблонов в скомпилированной двоичной форме вместо формы исходного кода. Это сократит время компиляции и соединения для приложений конечного пользователя. Например. std::basic_string<char> и std::basic_string<wchar_t> могут быть явно инстанцированы в распределении STL, избегая работы с его экземпляром в каждой единицы перевода.

Явное создание экземпляров также полезно, если вы хотите инкапсулировать реализацию шаблона и хотите, чтобы этот шаблон использовался только с известным набором типов. В этом случае вы можете размещать только объявления функций шаблона (бесплатно или члены) в файле заголовка (.h/.hpp) и определять их в единицах перевода (.cpp).

Пример:

 // numeric_vector.h
 //////////////////////////////////////////////////
 template <typename T> class numeric_vector
 {
    ...
    void sort();
 };


 // numeric_vector.cpp
 //////////////////////////////////////////////////
 // We know that it shall be used with doubles and ints only,
 // so we explicitly instantiate it for doubles and ints
 template class numeric_vector<int>;
 template class numeric_vector<double>;

 // Note that you could instantiate only specific
 // members you need (functions and static data), not entire class:
 template void numeric_vector<float>::sort();

 template <typename T> void numeric_vector<T>::sort()
 {
   // Implementation
   ...
 }

Также явное создание экземпляра может быть полезно, когда вам нужен экземпляр типа из шаблона, но внутри какой-либо конструкции синтаксиса, которая сама не запускает сам экземпляр. некоторые мета-функции, специфичные для компилятора, такие как __declspec(uuid) в Visual Studio.

Обратите внимание на разницу с другим методом, который может быть использован для инкапсуляции реализации - явная специализация. С помощью конкретной специализации вы должны предоставить конкретное определение для каждого специализированного типа. С явным конкретизацией вы имеете одно определение шаблона.

Рассмотрим тот же пример с явной специализацией:

Пример:

 // numeric_vector.h
 //////////////////////////////////////////////////
 template <typename T> class numeric_vector
 {
    ...
    void sort();
 };

 template <> class numeric_vector<int>
 {
    ...
    void sort();
 };

 template <> class numeric_vector<double>
 {
    ...
    void sort();
 };

 // Specializing separate members is also allowed
 template <> void numeric_vector<float>::sort();

 // numeric_vector.cpp    
 //////////////////////////////////////////////////
 void numeric_vector<int>::sort()
 {
   // Implementation for int
   ...
 }

 void numeric_vector<double>::sort()
 {
   // Implementation for double
   ...
 }

 void numeric_vector<float>::sort()
 {
   // Implementation for float       
   ...
 }

Ответ 3

Наличие явной специализации позволяет скрыть реализацию, которая, как вы знаете, обычно невозможна с шаблонами.

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

Итак, вы можете использовать

lib::Vector<MyShape>

с некоторыми базовыми функциями, предоставляемыми lib::Vector, и основными реализациями, и если вы использовали его со своими классами (некоторые, не все)

lib::Vector<lib::Polygon>

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

Ответ 4

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