the template guide geeksforgeeks example c++ templates

template - Almacenamiento de definiciones de funciones de plantilla de C++ en un archivo.CPP



typedef c++ (11)

¡Hora de una actualización! Cree un archivo en línea (.inl, o probablemente cualquier otro) y simplemente copie todas sus definiciones en él. Asegúrese de agregar la plantilla sobre cada función ( template <typename T, ...> ). Ahora, en lugar de incluir el archivo de encabezado en el archivo en línea, haga lo contrario. Incluya el archivo en línea después de la declaración de su clase ( #include "file.inl" ).

Realmente no sé por qué nadie ha mencionado esto. No veo inconvenientes inmediatos.

Tengo algún código de plantilla que preferiría haber almacenado en un archivo CPP en lugar de en línea en el encabezado. Sé que esto se puede hacer siempre que se sepa qué tipos de plantillas se utilizarán. Por ejemplo:

archivo .h

class foo { public: template <typename T> void do(const T& t); };

archivo .cpp

template <typename T> void foo::do(const T& t) { // Do something with t } template void foo::do<int>(const int&); template void foo::do<std::string>(const std::string&);

Tenga en cuenta las dos últimas líneas: la función foo :: do template solo se usa con ints y std :: strings, por lo que esas definiciones significan que la aplicación se vinculará.

Mi pregunta es: ¿es un hack desagradable o funcionará con otros compiladores / enlazadores? Solo estoy usando este código con VS2008 en este momento, pero desearé transferir a otros entornos.


El problema que describe se puede resolver definiendo la plantilla en el encabezado o mediante el enfoque que describió anteriormente.

Recomiendo leer los siguientes puntos de C ++ FAQ Lite :

Entran en muchos detalles sobre estos (y otros) problemas de plantillas.


Esa es una forma estándar de definir funciones de plantilla. Creo que hay tres métodos que leo para definir plantillas. O probablemente 4. Cada uno con sus pros y sus contras.

  1. Definir en definición de clase. No me gusta esto en absoluto porque creo que las definiciones de clase son estrictamente de referencia y deberían ser fáciles de leer. Sin embargo, es mucho menos complicado definir plantillas en clase que fuera. Y no todas las declaraciones de plantillas están en el mismo nivel de complejidad. Este método también hace que la plantilla sea una plantilla verdadera.

  2. Defina la plantilla en el mismo encabezado, pero fuera de la clase. Esta es mi forma preferida la mayoría de las veces. Mantiene su definición de clase ordenada, la plantilla sigue siendo una verdadera plantilla. Sin embargo, requiere una nomenclatura completa que puede ser complicada. Además, su código está disponible para todos. Pero si necesita que su código esté en línea, esta es la única manera. También puede lograr esto creando un archivo .INL al final de sus definiciones de clase.

  3. Incluya el header.h y la implementación.CPP en su main.CPP. Creo que así es como se hace. No tendrá que preparar ninguna instancia previa, se comportará como una verdadera plantilla. El problema que tengo con él es que no es natural. Normalmente no incluimos y esperamos incluir archivos de origen. Supongo que desde que incluyó el archivo fuente, las funciones de la plantilla se pueden alinear.

  4. Este último método, que fue el método publicado, es definir las plantillas en un archivo fuente, al igual que el número 3; pero en lugar de incluir el archivo fuente, creamos una instancia previa de las plantillas a las que necesitaremos. No tengo ningún problema con este método y es útil a veces. Tenemos un gran código, no puede beneficiarse de estar en línea, así que simplemente póngalo en un archivo CPP. Y si conocemos instancias comunes y podemos predefinirlas. Esto nos evita escribir básicamente lo mismo 5, 10 veces. Este método tiene la ventaja de mantener nuestro código propietario. Pero no recomiendo poner pequeñas funciones de uso regular en los archivos CPP. Como esto reducirá el rendimiento de su biblioteca.

Tenga en cuenta que no estoy al tanto de las consecuencias de un archivo obj hinchado.


Este código está bien formado. Solo debe prestar atención a que la definición de la plantilla es visible en el punto de creación de instancias. Para citar el estándar, § 14.7.2.4:

La definición de una plantilla de función no exportada, una plantilla de función miembro no exportada, una función miembro no exportada o un miembro de datos estáticos de una plantilla de clase estará presente en cada unidad de traducción en la que se haya creado una instancia explícita.


Esto debería funcionar bien en todas partes se admiten las plantillas. La creación de instancias explícitas de plantillas es parte del estándar C ++.


Esto definitivamente no es un truco desagradable, pero tenga en cuenta el hecho de que tendrá que hacerlo (la especialización de la plantilla explícita) para cada clase / tipo que quiera usar con la plantilla dada. En el caso de que MUCHOS tipos soliciten la creación de instancias de plantilla, puede haber MUCHAS líneas en su archivo .cpp. Para solucionar este problema, puede tener un TemplateClassInst.cpp en cada proyecto que use para que tenga un mayor control de qué tipos se crearán instancias. Obviamente, esta solución no será perfecta (también conocida como bala de plata) ya que podría terminar rompiendo la ODR :).


Hay, en el último estándar, una palabra clave ( export ) que ayudaría a aliviar este problema, pero no está implementado en ningún compilador del que yo sepa, aparte de Comeau.

Vea las FAQ-lite sobre esto.


No hay nada malo con el ejemplo que has dado. Pero debo decir que creo que no es eficiente almacenar definiciones de funciones en un archivo cpp. Solo entiendo la necesidad de separar la declaración y la definición de la función.

Cuando se usa junto con la creación de instancias de clase explícita, la Biblioteca de verificación de concepto de Boost (BCCL) puede ayudarlo a generar código de función de plantilla en archivos cpp.


Para otros en esta página que se preguntan cuál es la sintaxis correcta (como lo hice yo) para la especialización explícita de plantillas (o al menos en VS2008), es lo siguiente ...

En su archivo .h ...

template<typename T> class foo { public: void bar(const T &t); };

Y en tu archivo .cpp

template <class T> void foo<T>::bar(const T &t) { } // Explicit template instantiation template class foo<int>;


Sí, esa es la forma estándar de hacer una especialización explícita de instancias. Como dijo, no puede crear una instancia de esta plantilla con otros tipos.

Edición: corregido basado en el comentario.


Tu ejemplo es correcto pero no muy portátil. También hay una sintaxis ligeramente más limpia que se puede usar (como lo indica @ namespace-sid).

Supongamos que la clase con plantilla es parte de alguna biblioteca que se va a compartir. ¿Deberían compilarse otras versiones de la clase de plantilla? ¿Se supone que el encargado de la biblioteca debe anticipar todos los usos posibles de la clase?

Un enfoque alternativo es una ligera variación en lo que tiene: agregue un tercer archivo que sea el archivo de implementación / creación de instancias de la plantilla.

archivo foo.h

// Standard header file guards omitted template <typename T> class foo { public: void bar(const T& t); };

archivo foo.cpp

// Always include your headers #include "foo.h" template <typename T> void foo::bar(const T& t) { // Do something with t }

archivo foo-impl.cpp

// Yes, we include the .cpp file #include "foo.cpp" template class foo<int>;

La única advertencia es que debe decirle al compilador que compile foo-impl.cpp lugar de foo.cpp ya que compilar este último no hace nada.

Por supuesto, puede tener varias implementaciones en el tercer archivo o tener múltiples archivos de implementación para cada tipo que quiera usar.

Esto permite mucha más flexibilidad cuando se comparte la clase de plantilla para otros usos.

Esta configuración también reduce los tiempos de compilación para las clases reutilizadas porque no está recompilando el mismo archivo de encabezado en cada unidad de traducción.