Pregunta

Considere el siguiente ejemplo mínimo que reproduce un problema en un proyecto mucho más grande:

espec.h:
#include <iostream>

class A
{
public:
    template<typename T>
    T test(const std::string& a)
    {
        std::cout << "DEFAULT CALLED WITH " << a << "\n";
        return T();
    }
};

OTROS.CPP:
#include "spec.h"

template<>
float A::test<float>(const std::string& a)
{
    std::cout << "SPECIAL CALLED WITH " << a << "\n";
    return float();
}

SPEC.CPP:
#include <iostream>
#include "spec.h"

int main()
{
    A a;
    a.test<int>("int");
    a.test<float>("float");
    return 0;
}

Compilación:
$ make
rm -f *.o lib.a output
clang++ -g other.cpp -c
clang++ -g spec.cpp -c
ar cr lib.a other.o
clang++ -g -o output lib.a spec.o
rm -f *.o output2
clang++ -g other.cpp -c
clang++ -g spec.cpp -c
clang++ -g -o output2 other.o spec.o

$ ./output
DEFAULT CALLED WITH int
DEFAULT CALLED WITH float

$ ./output2
DEFAULT CALLED WITH int
SPECIAL CALLED WITH float

Pregunta:

¿Por qué está sucediendo esto?¿Se está despojando de alguna manera?¿Cuál es la diferencia entre lib.a y el uso de archivos de objetos directos?- -)

¡Gracias!

¿Fue útil?

Solución

de la sección 14.7.3p6:

Si una plantilla, una plantilla miembro o un miembro de una plantilla de clase se especializa explícitamente, entonces que la especialización se declarará antes del primer uso de esa especialización que cause una instanciación implícita, en cada unidad de traducción. en el que se produce tal uso ; No se requiere diagnóstico. Si el programa no proporciona una definición para una especialización explícita y la especialización se usa de una manera que causaría una instanciación implícita o el miembro es una función de miembro virtual, el programa está mal formado, no se requiere diagnóstico.

Su programa está mal formado porque usó la especialización en SPEC.CPP sin declararla primero en esa unidad de traducción. O, como dice el siguiente párrafo:

La colocación de las declaraciones de especialización explícitas para las plantillas de la función, las plantillas de clase, las funciones de los miembros de las plantillas de clase, los datos de los datos estáticos de las plantillas de clase, las clases de miembros de las plantillas de clase, las enumeraciones de los miembros de las plantillas de clase, las plantillas de la clase de los miembros de las plantillas de la clase, la función de los miembros Plantillas de plantillas de clase, Funciones para miembros de las plantillas de miembros de plantillas de clase, Funciones miembros de las plantillas de miembros de las clases sin plantillas, plantillas de funciones de miembros de las clases de miembros de las plantillas de clase, etc., y la colocación de declaraciones de especialización parcial de plantillas de clase, miembro Las plantillas de clase de clases sin plantillas, plantillas de clase de miembros de plantillas de clase, etc., pueden afectar si un programa está bien formado de acuerdo con el posicionamiento relativo de las declaraciones de especialización explícitas y sus puntos de instancias en la unidad de traducción, como se especifica anteriormente y abajo.

Al escribir una especialización, tenga cuidado con su ubicación;
o para hacerlo compilarlo será una prueba de un ajuste como para encender su autoinmolación.

que voto por lo el párrafo ausomésped en todo el estándar .

Otros consejos

La respuesta de Ben Voigt es correcta, pero quiero agregar un poco a él.

Esencialmente está obteniendo dos versiones diferentes de la función, una en otros.O y una en espec.O (generada por la plantilla en línea).El enlazador está diseñado para elegir uno y solo uno, lo que hace que se supongan que ambos son idénticos a medida que se requiere la norma.En el primer caso, el enlazador solo retirará una definición de una biblioteca si el símbolo ya no está definido.Dado que se define en SPEC.O, la definición de la biblioteca no se usa.

Con la definición en el encabezado, cada unidad de traducción puede crear su propia instanciación.Por lo tanto, nunca hay un símbolo indefinido que hace referencia a su versión especializada.En consecuencia, el archivo de objeto con la versión especializada no se incluye al mirar la biblioteca: no define ningún símbolo indefinido.Cuando se incluyen explícitamente el archivo de objeto mientras se vincula, el enlazador no tiene más remedio que incluirlo.Sin embargo, debe declarar todas las especializaciones: sin la declaración, el compilador no tiene ni idea de que la versión general no sea aplicable.Lo que sucede realiza esta versión, ya sea que se use o no, por lo tanto, depende de la forma en que se trata el símbolo.

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