c++ - son - ¿Cuándo usarías la creación de instancias explícita de la plantilla?
participacion ciudadana pdf (4)
Si realmente no le gusta definir funciones de plantilla en archivos de encabezado, puede definir las funciones en un archivo de origen separado y usar la creación de instancias explícitas para crear instancias de todas las versiones que usa. Entonces solo necesita una declaración directa en su archivo de encabezado en lugar de la definición completa.
Acabo de leer acerca de la creación de instancias explícitas de la plantilla:
template struct MyStruct<long>;
Se describió como "bastante raro", entonces ¿en qué circunstancias sería útil?
Uno de los casos de uso es ocultar las definiciones del usuario final.
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
}
La creación de instancias explícitas está diseñada para optimizar el uso de bibliotecas de plantillas proporcionando algunas de las instancias de plantilla (mayormente utilizadas) en formato binario compilado en lugar de en formato de código fuente. Esto reducirá el tiempo de compilación y enlace para las aplicaciones del usuario final. Ej. std::basic_string<char>
y std::basic_string<wchar_t>
se pueden crear instancias explícitas en la distribución STL para evitar el trabajo en su creación de instancias en cada unidad de traducción.
La creación de instancias explícitas también es útil cuando desea encapsular la implementación de plantillas y desea que esta plantilla se use solo con conjuntos de tipos bien conocidos. En este caso, puede colocar solo declaraciones de funciones de plantilla (gratuitas o miembros) en el archivo de encabezado ( .h/.hpp
) y definirlas en la unidad de traducción ( .cpp
).
Ejemplo:
// 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
...
}
También la creación de instancias explícitas puede ser útil cuando se necesita un tipo de instancia de una plantilla, pero dentro de una construcción de sintaxis que no desencadena la creación de instancias, por ejemplo, alguna meta-función específica del compilador como __declspec(uuid)
en Visual Studio .
Tenga en cuenta la diferencia con otra técnica que podría utilizarse para la encapsulación de implementación: especialización explícita. Con especialización explícita, debe proporcionar una definición específica para cada tipo que se especializará. Con la creación de instancias explícitas, tiene una definición de plantilla única.
Considere el mismo ejemplo con especialización explícita:
Ejemplo:
// 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
...
}
Tener una especialización explícita le permite ocultar la implementación, que, como usted sabe, generalmente es imposible con las plantillas.
He visto esta técnica solo una vez en una biblioteca que manejaba geometría, y proporcionaban su propia clase vectorial.
Entonces podrías usar
lib::Vector<MyShape>
con algunas funcionalidades básicas que lib::Vector
proporcionó, e implementaciones básicas, y si las usó con sus clases (algunas, no todas)
lib::Vector<lib::Polygon>
usarías la especialización explícita. No tendrías acceso a la implementación, pero apuesto a que algunas optimizaciones hardcore estaban ocurriendo detrás de escena allí.