es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Visibilidad de símbolos de C++ para la instanciación explícita de plantillas.

Creo una biblioteca compartida y uso la visibilidad de símbolos “ocultos” por defecto, es decir, tengo que modificar explícitamente la visibilidad de todo lo que se debe exportar. Además, defino plantillas en los archivos de encabezado e instancio explícitamente en los archivos fuente de la biblioteca para garantizar la compilación (y ocultar la implementación de los usuarios de la biblioteca). Para este archivo de encabezado foo.hpp

#include <gmpxx.h>

template <typename number="">
__attribute__((visibility("default")))
Number add(const Number& a, const Number& b);

y este archivo fuente foo.cpp

#include "foo.hpp"

template <typename number="">
Number add(const Number& a, const Number& b)
{
  return a + b;
}

template double add(const double& a, const double& b);
template int add(const int& a, const int& b);
template mpq_class add(const mpq_class& a, const mpq_class& b);

la compilación con

g++ -fPIC -fvisibility=hidden -c foo.cpp
g++ -fPIC -shared -o libfoo.so foo.o

arroja los siguientes símbolos (relevantes) (obtenidos mediante nm -CD libfoo.so):

gmpq_add
_gmpq_init
double add<double>(double const&, double const&)
int add<int>(int const&, int const&)

Sin embargo, esperaría también un símbolo para la implementación de mpq_class. Por supuesto, si ahora enlazo con esta biblioteca e intento llamar a add<mpq_class>, obtengo un error de símbolo no definido. Puedo forzar la exportación agregando una instancia explícita para mpq_class en foo.cpp que esté marcada explícitamente para su exportación:

template <>
__attribute__((visibility("default")))
mpq_class add(const mpq_class& a, const mpq_class& b)
{
  return a + b;
}

Por supuesto, esto no tiene mucho sentido ya que duplico el código o tengo que derivar hacia una implementación conjunta para cada función de este tipo. Para las clases de plantillas, parece que esto solo ocurre para los constructores y destructores, pero no para los miembros.

Me pregunto por qué sucede esto. Supongo que esto se debe de alguna manera al hecho de que mpq_class en sí es una clase de plantilla, pero me parece extraño.</gmpxx.h>

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    El problema aquí es que mpq_class es una clase de plantilla y su implementación no se está instanciando explícitamente en un contexto visible. Esto significa que el compilador no está generando el código de objeto necesario para la función add<mpq_class>, ya que no sabe cuál debería ser la implementación de mpq_class.

    Para solucionar esto, una solución es instanciar explícitamente la función add<mpq_class> en un contexto visible, como se muestra en el ejemplo. Alternativamente, la implementación de mpq_class podría ser instanciada explícitamente en un contexto visible, lo que también debería permitir compilar la función add<mpq_class>.

    Vale la pena señalar que este problema no es específico de C++ o bibliotecas compartidas: puede ocurrir en cualquier situación en la que se utilicen plantillas y su implementación no se instancie explícitamente en un contexto visible.

Comments are closed.