2010-09-20 4 views
37

¿Por qué la implementación y la declaración de una clase de plantilla deben estar en el mismo archivo de encabezado? ¿Podría alguno de ustedes explicarlo por ejemplo?¿Por qué la implementación y la declaración de una clase de plantilla deben estar en el mismo archivo de encabezado?

+7

tienen que estar visibles dentro de la misma unidad de compilación.pueden estar en archivos diferentes si ambos están incluidos – Anycorn

+2

De hecho, no es raro dividir la declaración y la implementación en dos archivos. El encabezado generalmente incluirá el archivo de implementación. – MSalters

+0

@MSalters: lo cual es problemático con las clases de plantilla, de lo que se trata esta pregunta. Desearía poder rechazar los comentarios. –

Respuesta

24

El compilador necesita tener acceso a toda la definición de plantilla (no solo a la firma) para generar código para cada instanciación de la plantilla, por lo que debe mover las definiciones de las funciones a su encabezado. Para obtener más información, visite The Inclusion Model.

+1

No, no es así. Podría escribir la definición manualmente en cada TU, pero, por supuesto, la convención de encabezado está diseñada para ayudarlo a evitar tales tonterías :) –

+0

@LightnessRacesinOrbit ¿puedo preguntar qué es TU? – athos

+0

@athos http://en.wikipedia.org/wiki/Translation_unit_%28programming%29 –

6

La definición de una plantilla de clase y la implementación de sus funciones miembro debe estar visible para cada lugar que la ejemplifique con un tipo distinto. es decir, para crear una instancia de myTemplate<int>, necesita ver la definición e implementación completa de myTemplate.

La forma más sencilla de hacerlo es colocar la definición de la plantilla y sus funciones miembro en el mismo encabezado, pero hay otras formas. Por ejemplo, podría poner las implementaciones de funciones miembro en un archivo separado que se incluyó por separado. Luego podría incluirlo desde el primer encabezado o solo incluir el archivo de implementación donde lo necesitó.

Por ejemplo, una práctica es crear una instancia explícita de una plantilla para un conjunto distinto de parámetros en un archivo .cpp y declarar esas instancias extern en el encabezado. De esta forma, esas instancias se pueden usar en otros archivos fuente sin que sea necesario que la implementación de las funciones del miembro de la plantilla sea visible. Sin embargo, a menos que incluya el archivo de implementación, no podrá usar otros conjuntos de parámetros de plantilla.

es decir, si tiene myTemplate<int> y myTemplate<std::string> define como extern entonces usted puede usarlos bien, pero si no se define myTemplate<double>extern entonces no se puede utilizar que sin la aplicación.

4

En el caso de una clase normal, la declaración es suficiente para la compilación, y las definiciones correspondientes serán vinculadas.

En el caso de las plantillas, el compilador también necesita la definición para generar el código.

La diferencia se explica mejor en el C++ FAQ.

4

No es necesario.

Lo que es necesario es que la definición de la plantilla sea visible en el momento de la instanciación (donde se usa) para que el compilador pueda derivar la clase/función de la plantilla en este momento.

Sin embargo, es muy común el uso de dos archivos de cabecera para las clases de plantilla:

// foo_fwd.hpp 
template <typename T, typename U> struct Foo; 

// foo.hpp 
#include "foo_fwd.hpp" 

template <typename T, typename U> struct Foo { typedef std::pair<T,U> type; }; 

Esto permite que aquellos que no necesitan la definición de plantilla completa para incluir una cabecera algo más ligero, por ejemplo:

//is_foo.hpp 
#include <boost/mpl/bool.hpp> 
#include "foo_fwd.hpp" 

template <typename Z> 
struct is_foo: boost::mpl::false_ {}; 

template <typename T, typename U> 
struct is_foo< Foo<T,U> >: boost::mpl::true_ {}; 

que puede acelerar un poco el tiempo de compilación.

Cuestiones relacionadas