Acerca de C ++ por qué la función de plantilla en la clase de plantilla solo se puede escribir en el archivo de encabezado

Reimpreso de: https://www.yht7.com/news/27097

De la codificación a la ejecución En
primer lugar, quiero discutir cómo un proyecto de C ++ genera archivos ejecutables a partir de archivos de texto.

Pre-compilación
Pre-compilación es a comandos de macro proceso de pre-compilados, como #include, #define, #ifdef, #pragma, etc.

Compilación La
compilación consiste en convertir el código fuente en el texto en lenguaje ensamblador que puede ser procesado directamente por la computadora. Cabe señalar aquí que C ++ utiliza una compilación separada (la compilación de cada archivo h y cpp es independiente).

El desarrollo de C ++ se usa ampliamente en la forma de desarrollo de declaración y realización por separado. El proceso de compilación es una compilación separada, lo que significa que cada archivo cpp se compila completamente por separado, y luego se genera cada archivo de objeto obj y, finalmente, se genera un archivo exe ejecutable a través del enlace del enlazador. Citado de: https://blog.csdn.net/uestclr/article/details/51372780

Linking
Compilation mencionó que C ++ usa una compilación separada, como el siguiente código:

Prueba.h

void test();

Test.cpp

#include "Test.h"
void test() {
    
    
    //todo
}

main.cpp

#include "test.h"
int main() {
    
    
    test();
    return 0;
}

Hasta ahora, se deben generar dos archivos durante la compilación: (en macOS)

Durante la compilación de Test.cpp.o
main.cpp.o
, cuando main.cpp llama a la función test (), no conoce la dirección de entrada de la función test (). El compilador registrará el símbolo de la función (test ()) en la tabla de importación de símbolos (debido a que el formato del archivo .a es el mismo que el archivo ejecutable, hay una tabla de importación de símbolos y una tabla de exportación de símbolos (tabla de importación y tabla de exportación) en dicho archivo, que asocian todos símbolos con sus direcciones).

De esta manera, el enlazador solo necesita encontrar la dirección del símbolo test () en la tabla de exportación de símbolos de Test.cpp.o, y luego hacer un procesamiento de compensación (porque los dos archivos .o están fusionados, por supuesto, la dirección tendrá una cierta compensación, este vinculador es claro) Escriba el elemento ocupado por test () en la tabla de importación de símbolos en main.cpp.o.

Función de plantilla
Volviendo al tema discutido al principio, la declaración y definición de la función de plantilla están escritas en dos archivos, y se informará un error cuando el compilador se vincule. Los ejemplos específicos son los siguientes:

Prueba.h

template<class T, T t>
void test(T a);

Test.cpp

#include "Test.h"
template<class T, T t>
void test(T a) {
    
    
    //todo
}

main.cpp

#include "Test.h"
int main() {
    
    
    test<int, 1>();
    return 0;
}

El compilador informó un error:

[ 18%] Linking CXX executable cpp_learning
Undefined symbols for architecture x86_64:
  "void test<int, 1>(int)", referenced from:
      main() in main.cpp.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Míralo para determinar el error en la fase de enlace.

¿por qué?

Restricciones en las funciones de la plantilla El
estándar C ++ establece claramente que cuando no se utiliza una plantilla, no se debe crear una instancia. Esto significa que no hay una definición de función de prueba en Test.cpp.o.

En un entorno de compilación independiente, el compilador no conoce la existencia de otro archivo .cpp al compilar un determinado archivo .cpp y no lo buscará (pondrá sus esperanzas en el vinculador cuando encuentre un símbolo pendiente). Este modo funciona bien sin una plantilla, pero se queda estupefacto cuando encuentra una plantilla, porque la plantilla se crea una instancia solo cuando es necesario, por lo que cuando el compilador solo ve la declaración de la plantilla, no puede instanciarla. Para transformar la plantilla, usted solo puede crear un símbolo con conexiones externas y esperar que el vinculador resuelva la dirección del símbolo. Sin embargo, cuando la instancia de la plantilla no se usa en el archivo .cpp que implementa la plantilla, el compilador es demasiado perezoso para crear una instancia. Por lo tanto, no hay una línea de código binario para la instancia de la plantilla en el .a de todo el proyecto. , por lo que el enlazador también está agotado. ---- Referencia: https://www.jianshu.com/p/dc94f0cbfcf7

La solución
es la siguiente:

Escriba la definición de la función de la plantilla en el archivo h;
use la función de la plantilla en el archivo cpp (para que la función de la plantilla se pueda instanciar en tiempo de compilación)

Supongo que te gusta

Origin blog.csdn.net/sinat_27382047/article/details/107739562
Recomendado
Clasificación