Visibilidad de la especialización de plantillas de la función C ++.

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

Si ahora llamo a SomeFunc() desde algún otro código (quizás 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 aplicación utiliza el formulario genérico (que causa problemas de tiempo de ejecución más adelante). ¿Por qué la diferencia? ¿Podría esto estar relacionado con las opciones del enlazador, etc.? Esto está en Linux, con g ++ 4.1.2.

Es un error tener una especialización para una plantilla que no es visible en el punto de la llamada. Desafortunadamente, los comstackdores no están obligados a diagnosticar este error y, a continuación, pueden hacer lo que quieran con su código (en la versión estándar está “mal formado, no se requiere diagnóstico”).

Técnicamente, debe definir la especialización en el archivo de encabezado, pero casi todos los comstackdores manejarán esto como cabría esperar: esto se soluciona en C ++ 11 con la nueva función “plantilla externa”:

 extern template<> SomeFunc(); 

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

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

Quiero decir, ¿hay algún lugar en el archivo A.h?

 template<> SomeFunc(); 

Si no, esa es probablemente la razón.

Tuve el mismo problema con gcc4, aquí es cómo lo resolví. Era una solución más simple de lo que me habían hecho creer en comentarios anteriores. Las ideas de las publicaciones anteriores fueron correctas, pero su syntax no funcionó para mí.

 ----------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"; } 

De acuerdo con las especificaciones, su plantilla de función especializada nunca debe llamarse fuera de fileA.C , a menos que export la definición de plantilla, que ningún comstackdor (excepto Comeau) admite actualmente (o tiene planeado para el futuro inmediato).

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

Creo que GCC puede exponer un error aquí al compartir su lista de plantillas instanciadas en las unidades de comstackción. Normalmente, esta es una optimización razonable, pero debería tener en cuenta las especializaciones de funciones que no parece hacer correctamente.

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

archivoA.h:

 namespace myNamespace { class classA { public: template  void SomeFunc() { ... } }; // The following line declares the specialization SomeFunc(). template <> void classA::SomeFunc(); // The following line externalizes the instantiation of the previously // declared specialization SomeFunc(). If the preceding line is omitted, // the following line PREVENTS the specialization of SomeFunc(); // SomeFunc() 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() 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(); } 

archivoA.C:

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

Brandon: eso es lo que pensé: la función especializada nunca debería ser llamada. Lo cual es cierto para la segunda aplicación que mencioné. Sin embargo, la primera aplicación llama claramente a la forma especializada, aunque la especialización no se declara en el archivo de encabezado.

Principalmente busco la iluminación aquí 🙂 porque la primera aplicación es una prueba de unidad, 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 declarando la especialización en el encabezado; pero, ¿qué otros errores similares podrían estar ocultos?)

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 fonts. Obtuve resultados diferentes dependiendo de si estaba usando una versión de depuración o una versión de lanzamiento. En Debug, el comstackdor se niega a incluir nada en línea, y el vinculador vinculaba la misma versión de la función sin importar el scope en la fuente. En Release, el comstackdor incorporó la versión que se haya definido en ese momento, y tienes diferentes versiones de la función.

En ninguno de los dos casos hubo advertencias. Yo sospechaba esto, por eso hice el experimento.

Supongo que las funciones de la plantilla se comportarían de la misma manera que otros comstackdores.

@ [anthony-williams],

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

explícita-especialización :
template <> statement

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 agregar SomeFunc() al encabezado también.