template plantillas c++ templates c++11 extern

template - plantillas c++



utilizando una plantilla externa(C++ 11) (4)

Figura 1: plantillas de funciones

TemplHeader.h

template<typename T> void f();

TemplCpp.cpp

template<typename T> void f(){ //... } //explicit instantation template void f<T>();

Main.cpp

#include "TemplHeader.h" extern template void f<T>(); //is this correct? int main() { f<char>(); return 0; }

¿Es esta la manera correcta de usar una extern template , o utilizo esta palabra clave solo para plantillas de clase como en la Figura 2?

Figura 2: plantillas de clase

TemplHeader.h

template<typename T> class foo { T f(); };

TemplCpp.cpp

template<typename T> void foo<T>::f() { //... } //explicit instantation template class foo<int>;

Main.cpp

#include "TemplHeader.h" extern template class foo<int>(); int main() { foo<int> test; return 0; }

Sé que es bueno poner todo esto en un archivo de cabecera, pero si creamos las plantillas con los mismos parámetros en varios archivos, obtendremos varias definiciones y el compilador las eliminará todas (excepto una) para evitar errores. ¿Cómo uso la extern template ? ¿Podemos usarlo solo para clases, o podemos usarlo para funciones también?

Además, la Figura 1 y la Figura 2 pueden ampliarse a una solución donde las plantillas están en un único archivo de encabezado. En ese caso, necesitamos usar la palabra clave de extern template para evitar múltiples instancias iguales. ¿Esto es solo para clases o funciones también?


El problema conocido con las plantillas es la distensión del código, que es consecuencia de generar la definición de la clase en cada módulo que invoca la especialización de la plantilla de la clase. Para evitar esto, comenzando con C ++ 0x, se podría usar la palabra clave extern delante de la especialización de plantilla de clase

#include <MyClass> extern class CMyClass<int>;

La instancia explícita de la clase de plantilla debería ocurrir solo en una sola unidad de traducción, preferiblemente la que tiene definición de plantilla (MyClass.cpp)

template class CMyClass<int>; template class CMyClass<float>;


Si ha utilizado extern para funciones anteriormente, se sigue exactamente la misma filosofía para las plantillas. si no, ir a través de funciones simples puede ayudar. Además, es posible que desee colocar los externos en el archivo de encabezado e incluir el encabezado cuando lo necesite.


Solo debe usar extern template para forzar al compilador a no crear una instancia de una plantilla cuando sabe que se creará una instancia en otro lugar. Se usa para reducir el tiempo de compilación y el tamaño del archivo de objeto.

Por ejemplo:

// header.h template<typename T> void ReallyBigFunction() { // Body } // source1.cpp #include "header.h" void something1() { ReallyBigFunction<int>(); } // source2.cpp #include "header.h" void something2() { ReallyBigFunction<int>(); }

Esto dará como resultado los siguientes archivos de objeto:

source1.o void something1() void ReallyBigFunction<int>() // Compiled first time source2.o void something2() void ReallyBigFunction<int>() // Compiled second time

Si ambos archivos están vinculados entre sí, se void ReallyBigFunction<int>() una función void ReallyBigFunction<int>() , lo que da como resultado el tiempo de compilación desperdiciado y el tamaño del archivo de objeto.

Para no perder el tiempo de compilación y el tamaño del archivo objeto, existe una palabra clave extern que hace que el compilador no compile una función de plantilla. Debe usar esto si y solo si sabe que se usa en el mismo binario en otro lugar.

Cambiando source2.cpp a:

// source2.cpp #include "header.h" extern template void ReallyBigFunction<int>(); void something2() { ReallyBigFunction<int>(); }

Producirá los siguientes archivos de objeto:

source1.o void something1() void ReallyBigFunction<int>() // compiled just one time source2.o void something2() // No ReallyBigFunction<int> here because of the extern

Cuando ambos se vinculen entre sí, el segundo archivo de objeto simplemente usará el símbolo del primer archivo de objeto. No es necesario descartar ni perder el tiempo de compilación y el tamaño del archivo de objeto.

Esto solo debe usarse dentro de un proyecto, como cuando utiliza una plantilla como vector<int> varias veces, debe usar extern en todos los archivos de origen, excepto uno.

Esto también se aplica a las clases y a la función como uno, e incluso a funciones de miembros de plantilla.


Wikipedia tiene la mejor descripción

En C ++ 03, el compilador debe instanciar una plantilla siempre que se encuentre una plantilla completamente especificada en una unidad de traducción. Si la plantilla se instancia con los mismos tipos en muchas unidades de traducción, esto puede aumentar drásticamente los tiempos de compilación. No hay forma de evitar esto en C ++ 03, por lo que C ++ 11 introdujo declaraciones de plantillas externas, análogas a las declaraciones de datos externas.

C ++ 03 tiene esta sintaxis para obligar al compilador a crear una instancia de una plantilla:

template class std::vector<MyClass>;

C ++ 11 ahora proporciona esta sintaxis:

extern template class std::vector<MyClass>;

que le dice al compilador que no cree una instancia de la plantilla en esta unidad de traducción.

La advertencia: nonstandard extension used...

Microsoft VC ++ solía tener una versión no estándar de esta característica desde hace algunos años (en C ++ 03). El compilador advierte sobre eso para evitar problemas de portabilidad con código que también debe compilarse en diferentes compiladores.

Mire la muestra en la página vinculada para ver que funciona aproximadamente de la misma manera. Puede esperar que el mensaje desaparezca con versiones futuras de MSVC, excepto, por supuesto, cuando se usan otras extensiones de compilador no estándar al mismo tiempo.