Pregunta

Suponga que un archivo de encabezado define una plantilla de función. Ahora suponga que dos archivos de implementación #include este encabezado, y cada uno de ellos tiene una llamada a la plantilla de función. En ambos archivos de implementación, la plantilla de función está instanciada con el mismo tipo.

// header.hh
template <typename T>
void f(const T& o)
{
    // ...
}

// impl1.cc
#include "header.hh"

void fimpl1()
{
    f(42);
}

// impl2.cc
#include "header.hh"

void fimpl2()
{
    f(24);
}

Uno puede esperar que el enlazador se queje de múltiples definiciones de f () . Específicamente, si f () no fuera una plantilla, ese sería el caso.

  • ¿Cómo es que el enlazador no se queja de múltiples definiciones de f () ?
  • ¿Se especifica en el estándar que el enlazador debe manejar esta situación con gracia? En otras palabras, ¿puedo contar siempre con programas similares a los anteriores para compilar y vincular?
  • Si el enlazador puede ser lo suficientemente inteligente como para desambiguar un conjunto de instancias de plantillas de funciones, ¿por qué no puede hacer lo mismo para las funciones regulares, dado que son idénticas como es el caso de las plantillas de funciones instanciadas?
¿Fue útil?

Solución

Para admitir C ++, el enlazador es lo suficientemente inteligente como para reconocer que todas tienen la misma función y descarta todas menos una.

EDITAR: aclaración: El vinculador no compara los contenidos de las funciones y determina que son iguales. Las funciones programadas están marcadas como tales y el vinculador reconoce que tienen las mismas firmas.

Otros consejos

El manual del compilador Gnu C ++ tiene una buena discusión de esto . Un extracto:

  

Las plantillas de C ++ son el primer idioma   Característica para requerir más inteligencia.   del medio ambiente que uno usualmente   encuentra en un sistema UNIX. De alguna manera el   compilador y enlazador tienen que asegurarse   que se produce cada instancia de plantilla   exactamente una vez en el ejecutable si   Es necesario, y no de otra manera.   Hay dos enfoques básicos para esto   problema, que se conoce como   Modelo Borland y el modelo Cfront.

     

modelo Borland

     

Borland C ++ resolvió la plantilla   problema de instanciación agregando el   Código equivalente de bloques comunes a   su enlazador el compilador emite   instancias de plantilla en cada traducción   unidad que los usa, y el enlazador   los colapsa juntos. La ventaja   De este modelo es que solo el enlazador.   tiene que considerar los archivos objeto   sí mismos; no hay externo   La complejidad de la que preocuparse. Esta   desventaja es ese tiempo de compilación   se incrementa porque el código de la plantilla   se está compilando repetidamente Código   escrito para este modelo tiende a   incluir definiciones de todas las plantillas   en el archivo de cabecera, ya que deben estar   visto para ser instanciado.

     

Modelo Cfront

     

El traductor AT & amp; T C ++, Cfront,   resolvió la instanciación de plantilla   problema creando la noción de un   repositorio de plantillas, automáticamente   lugar mantenido donde la plantilla   Las instancias son almacenadas. Un más moderno   la versión del repositorio funciona como   Sigue: Como archivos de objetos individuales.   Se construyen, el compilador coloca cualquier   definiciones de plantillas y   instancias encontradas en el   repositorio. En el momento del enlace, el enlace   el contenedor agrega los objetos en el   repositorio y compila cualquier necesidad   instancias que no eran previamente   emitido Las ventajas de este modelo.   son una velocidad de compilación más óptima y   la capacidad de utilizar el enlazador del sistema;   para implementar el modelo de Borland a   proveedor compilador también necesita reemplazar   el enlazador Las desventajas son   complejidad enormemente aumentada, y por lo tanto   potencial de error; por algún código   esto puede ser igual de transparente, pero   en la práctica puede ser muy difícil   para construir múltiples programas en uno   Directorio y un programa en múltiples   directorios. Código escrito para esto   modelo tiende a separar definiciones de   plantillas de miembros no en línea en una   archivo separado, que debería ser   compilado por separado.

     

Cuando se usa con GNU ld versión 2.8 o   más tarde en un sistema ELF como   GNU / Linux o Solaris 2, o en   Microsoft Windows, G ++ es compatible con   Modelo de Borland. En otros sistemas, G ++   no implementa ninguno de los modelos automáticos.

Esto es más o menos un caso especial solo para plantillas.

El compilador solo genera las instancias de plantilla que realmente se utilizan. Como no tiene control sobre qué código se generará a partir de otros archivos de origen, debe generar el código de la plantilla una vez para cada archivo, para asegurarse de que el método se genere en absoluto.

Dado que es difícil resolver esto (el estándar tiene una palabra clave extern para las plantillas, pero g ++ no lo implementa) el enlazador simplemente acepta las definiciones múltiples.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top