2010-03-20 9 views

Respuesta

7

Si desea utilizar una plantilla en otra unidad de traducción (es decir, otro archivo fuente), debe (casi siempre) definirla en el archivo de encabezado. (Hay excepciones, como los comentarios a continuación señalan, pero en mi humilde opinión esta es una buena regla).

Lo mismo se aplica si desea usar una función en línea de otra unidad de traducción.

De lo contrario, debe poner la implementación en un archivo .cpp separado para minimizar las dependencias.

+2

En cuanto a las plantillas, no es estrictamente cierto que debe poner las definiciones de función (miembro) en el archivo de encabezado. Puede poner las definiciones en un archivo fuente y usar la creación de instancias explícitas para hacer que las especializaciones particulares estén disponibles ... –

+0

@STingRaySC Sí, tuve algunos recuerdos vagos de C++ Templates de que es posible, aunque nunca lo he hecho yo mismo. Sin embargo, traté de dar una regla general que es buena para los principiantes y casi siempre aplicable. Entrar en los casos especiales es para los expertos (de los que no soy uno :-) –

+0

Y no tiene que proporcionar implementaciones de plantilla en el archivo de encabezado si su compilador admite 'export' – smerlin

3

Comprender este problema consiste básicamente en comprender cómo funcionan las unidades de compilación de C++. Las cosas en los archivos de encabezado se pegan básicamente en el código fuente de un conjunto completo de unidades de compilación mediante declaraciones #include. Cada unidad de compilación se compila en un archivo de objetos, los archivos de objeto se vinculan y se generan conflictos debido a que esas cosas se replican por todas partes.

Las excepciones son cosas que (históricamente, al menos) no entran en el archivo objeto porque el compilador las trata directamente (por ejemplo, funciones en línea) y cosas que no se pueden compilar en una unidad y luego enlazar a otro porque no están completamente definidos (plantillas). Las funciones de plantilla a menudo obtienen idénticas instancias en varias unidades de compilación, y el enlazador tiene una inteligencia especial para descartar los duplicados.

Esto significa que la separación de la interfaz y la implementación en los archivos de encabezado y cuerpo no es muy clara. Ada tiene una separación mucho más limpia, pero un proceso de construcción más complejo para compensar el IIRC. Java simplemente dejó caer los archivos separados para la interfaz y la implementación.

Los enlazadores se volvieron mucho más sofisticados a lo largo de los años y asumieron parte del trabajo del compilador, y muchas de estas explicaciones simplemente están equivocadas en estos días, pero los patrones básicos permanecen. Las funciones de plantilla y las funciones en línea pueden (y a menudo deben) ir en el encabezado, junto con todas las declaraciones compartidas de don't-direct-generate-object-code. Las definiciones de funciones normales no deberían estar en un archivo de encabezado.

+0

En realidad, los vinculadores no son tan inteligentes con las instancias de 'plantilla'. Básicamente tomarán el primero que encuentren y se basarán en ** ODR ** (Regla de una definición). Puede provocar errores difíciles de encontrar si solo una parte de las instancias 'Foo ' utiliza una especialización. –

Cuestiones relacionadas