full compiler compile compilador c++ linux templates linker g++

compiler - Visibilidad de la especialización de plantilla de la función C++



install g++ (9)

¿Ha agregado un prototipo con parámetros a su archivo de encabezado?

Quiero decir, ¿hay algún lugar en fileA.h

template<> SomeFunc<int>();

Si no, esa es probablemente la razón.

Supongamos que tengo fileA.h que declara una clase classA con la función de plantilla SomeFunc<T>() . Esta función se implementa directamente en el archivo de encabezado (como es habitual para las funciones de plantilla). Ahora agrego una implementación especializada de SomeFunc() (como para SomeFunc<int>() ) en fileA.C (es decir, no en el archivo de encabezado).

Si ahora llamo SomeFunc<int>() desde algún otro código (tal vez también desde otra biblioteca), ¿llamaría a la versión genérica o la especialización?

Tengo este problema en este momento, donde la clase y la función viven en una biblioteca que es utilizada por dos aplicaciones. Y una aplicación utiliza correctamente la especialización, mientras que otra usa la forma genérica (lo que causa problemas de tiempo de ejecución más adelante). ¿Por qué la diferencia? ¿Podría esto estar relacionado con las opciones del vinculador, etc.? Esto está en Linux, con g ++ 4.1.2.


@ [anthony-williams],

¿Estás seguro de que no estás confundiendo las declaraciones de extern template con instancias de extern template ? Por lo que veo, la extern template solo se puede usar para la instanciación explícita, no para la especialización (lo que implica una instanciación implícita). [temp.expl.spec] no menciona la palabra clave extern :

especialización explícita :
template <> declaración


A menos que la función de plantilla especializada también aparezca en el archivo de encabezado, la otra aplicación no tendrá conocimiento de la versión especializada. La solución es añadir SomeFunc<int>() al encabezado también.


Brandon: eso es lo que pensé: la función especializada nunca debería llamarse. Lo cual es cierto para la segunda aplicación que mencioné. La primera aplicación, sin embargo, claramente llama a la forma especializada a pesar de que la especialización no está declarada en el archivo de encabezado.

Principalmente busco la iluminación aquí :-) porque la primera aplicación es una prueba unitaria, y es desafortunado tener un error que no aparece en la prueba sino en la aplicación real ...

(PD: He solucionado este error específico, de hecho al declarar la especialización en el encabezado, pero ¿qué otros errores similares todavía pueden estar ocultos?)


Como dice Anthony Williams, la construcción de extern template es la forma correcta de hacerlo, pero dado que su código de muestra está incompleto y tiene múltiples errores de sintaxis, aquí hay una solución completa.

fileA.h:

namespace myNamespace { class classA { public: template <class T> void SomeFunc() { ... } }; // The following line declares the specialization SomeFunc<int>(). template <> void classA::SomeFunc<int>(); // The following line externalizes the instantiation of the previously // declared specialization SomeFunc<int>(). If the preceding line is omitted, // the following line PREVENTS the specialization of SomeFunc<int>(); // SomeFunc<int>() will not be usable unless it is manually instantiated // separately). When the preceding line is included, all the compilers I // tested this on, including gcc, behave exactly the same (throwing a link // error if the specialization of SomeFunc<int>() is not instantiated // separately), regardless of whether or not the following line is included; // however, my understanding is that nothing in the standard requires that // behavior if the following line is NOT included. extern template void classA::SomeFunc<int>(); }

fileA.C:

#include "fileA.h" template <> void myNamespace::classA::SomeFunc<int>() { ... }


En Microsoft C ++, hice un experimento con funciones en línea. Quería saber qué pasaría si definiera versiones incompatibles de una función en diferentes fuentes. Obtuve diferentes resultados dependiendo de si estaba usando una versión de Debug o una versión de Release. En Debug, el compilador se rehúsa a alinear cualquier cosa, y el enlazador estaba vinculando la misma versión de la función, sin importar el alcance de la fuente. En Release, el compilador ingresó la versión que se haya definido en ese momento, y usted tiene diferentes versiones de la función.

En ninguno de los casos hubo advertencias. De alguna manera sospeché esto, y por eso hice el experimento.

Supongo que las funciones de plantilla se comportarían igual que otros compiladores.


Es un error tener una especialización para una plantilla que no está visible en el momento de la llamada. Desafortunadamente, los compiladores no están obligados a diagnosticar este error, y luego pueden hacer lo que quieran con su código (en la norma, está "mal formado, no se requiere diagnóstico").

Técnicamente, debe definir la especialización en el archivo de encabezado, pero casi todos los compiladores manejarán esto como era de esperar: esto se soluciona en C ++ 11 con la nueva función de "plantilla externa":

extern template<> SomeFunc<int>();

Esto declara explícitamente que la especialización particular se define en otra parte. Muchos compiladores ya lo soportan, algunos con y sin el extern .


Según las especificaciones, su plantilla de función especializada nunca se debe llamar fuera de fileA.C , a menos que export la definición de la plantilla, que ningún compilador (excepto Comeau) admite actualmente (o tiene planeado para el futuro previsible).

Por otro lado, una vez que se crea una instancia de la plantilla de función, hay una función visible para el compilador que ya no es una plantilla. GCC puede volver a utilizar esta definición en diferentes unidades de compilación porque el estándar establece que cada plantilla solo se instanciará una vez para un conjunto determinado de argumentos de tipo [temp.spec]. Aún así, dado que la plantilla no se exporta, esto debe limitarse a la unidad de compilación.

Creo que GCC puede exponer un error aquí al compartir su lista de plantillas creadas a través de unidades de compilación. Normalmente, esta es una optimización razonable, pero debe tener en cuenta las especializaciones de función que no parece funcionar correctamente.


Tuve el mismo problema con gcc4, así es como lo resolví. Era una solución más simple de lo que me llevaron a creer en comentarios anteriores. Las ideas de publicaciones anteriores eran correctas, pero su sintaxis no me funcionaba.

----------header----------------- template < class A > void foobar(A& object) { std::cout << object; } template <> void foobar(int); ---------source------------------ #include "header.hpp" template <> void foobar(int x) { std::cout << "an int"; }