Я только что читал о явном экземпляре шаблона:
template struct MyStruct<long>;
Он был описан как "довольно редкий", поэтому при каких обстоятельствах это было бы полезно?
Я только что читал о явном экземпляре шаблона:
template struct MyStruct<long>;
Он был описан как "довольно редкий", поэтому при каких обстоятельствах это было бы полезно?
Один из вариантов использования - скрыть определения от конечного пользователя.
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
}
Явное создание экземпляров предназначено для оптимизации использования библиотек шаблонов, предоставляющих некоторые (в основном используемые) экземпляры шаблонов в скомпилированной двоичной форме вместо формы исходного кода. Это сократит время компиляции и соединения для приложений конечного пользователя. Например. 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
...
}
Наличие явной специализации позволяет скрыть реализацию, которая, как вы знаете, обычно невозможна с шаблонами.
Я видел эту технику только один раз в библиотеке, которая обрабатывала геометрию, и они предоставили бы свой собственный векторный класс.
Итак, вы можете использовать
lib::Vector<MyShape>
с некоторыми базовыми функциями, предоставляемыми lib::Vector
, и основными реализациями, и если вы использовали его со своими классами (некоторые, не все)
lib::Vector<lib::Polygon>
вы должны использовать явную специализацию. У вас не было бы доступа к реализации, но я уверен, что некоторые хардкорные оптимизации продолжались за кулисами.
Если вам действительно не нравится определять функции шаблона в файлах заголовков, вы можете определить функции в отдельном исходном файле и использовать явное создание шаблона для создания экземпляров всех используемых вами версий. Тогда вам нужно только форвардные объявления в файле заголовка вместо полного определения.