2012-01-17 9 views
6

Intento ajustar una función de plantilla con la ayuda del enlazador de GNU wrap opción. El código es el siguiente:Envoltura de la función de plantilla C++

// f.h 
template<typename T> 
void f(T t) { 
} 

// bar.h 
void bar(); 

// bar.cpp 
#include "bar.h" 
#include "f.h" 

void bar() { 
    f(42); 
} 

// test.cpp 
extern "C" { 
    extern void __real__Z1fIiEvT_(int i); 
    void __wrap__Z1fIiEvT_(int i) { 
    __real__Z1fIiEvT_(i); 
    } 
} 

int main() { 
    bar(); 
} 

el código mostrado anteriormente se vincula con el siguiente comando:

g++ -Xlinker -wrap=_Z1fIiEvT_ -o test test.o bar.o 

Por desgracia, esto no funciona y siempre la función original f se llama en lugar de mi versión envuelta __wrap__Z1fIiEvT_. ¿Ves algún error que haya cometido?

Editado: Como estaba previsto, añado la salida de nm aquí para asegurarse de que el que no he hecho ningún error con el nombre revuelto de la función de plantilla:

$ g++ -c bar.cpp -o bar.o 
$ nm bar.o 
0000000000000000 W _Z1fIiEvT_ 
+1

Verifique que está llamando a la función decorada correcta utilizando 'nm' o una herramienta similar. Agregar el resultado relevante de eso a la pregunta puede ser útil. – uesp

+0

No debería f (42); ser f (42)? –

+1

@ Fire-Dragon-DoL - Las funciones de la plantilla inferirán sus tipos de argumentos a partir de los argumentos, y dado que int es el tipo de un entero entero no decorado, esto funciona bien. Si f fuera una clase, entonces el argumento de la plantilla debería ser explícito. – Marc

Respuesta

1

De http://linux.die.net/man/1/ld:

--wrap = símbolo
Utilice una función de contenedor para el símbolo. Cualquier referencia indefinida al símbolo se resolverá en "_ wrap symbol". Cualquier referencia indefinida a "_ real símbolo" se resolverá en el símbolo.

Creo que la palabra "indefinido" podría ser la clave aquí. Su símbolo de interés se define claramente en bar.o, y la salida nm lo confirma, ya que los símbolos indefinidos están marcados con "U", no "W".


Actualización:

supongo que por lo tanto no es posible envolver las funciones de plantilla?

Creo que depende más de dónde se define (o instancia) la función, y si esta definición está disponible para el vinculador. En su caso, si definió una función que no sea de plantilla en bar.cpp donde se usa, el resultado sería el mismo. Incluso si definió la función en bar.cpp pero la usó en main.cpp, supongo que sería la misma, aunque no del todo segura (puede intentarlo). Y estoy seguro de que si vinculó bar.cpp y main.cpp en diferentes módulos (una biblioteca compartida y un ejecutable), entonces sería capaz de ajustar una función de bar.cpp utilizada en main.cpp, de nuevo no importa ya sea una plantilla o no.


Actualización 2: No estaba segura, pero Mike confirmó con el experimento (véase su propia respuesta y los comentarios allí) que envuelve funciona si el símbolo no está definido en un fichero objeto, incluso si dicho archivo objeto está vinculado junto con otro archivo objeto que contiene la definición del símbolo. ¡Estupendo!

+0

Tienes razón. Como el compilador genera código para la plantilla de función instanciada, ya no es un símbolo indefinido y, por lo tanto, el enlazador no lo ajustará a "_wrap_symbol". Supongo que, por lo tanto, no es posible ajustar las funciones de la plantilla. – Mike

1

Los comentarios fueron útiles, pero no creo que sea necesario dividirlo en un archivo ejecutable y una biblioteca (compartida). La clave es tener una declaración directa para la función de plantilla en el origen de la llamada y crear una instancia de la función de plantilla con el tipo utilizado en una unidad de traducción separada. Esto garantiza que f no está definido en la barra.o:

//bar.cpp 
#include "bar.h" 

template<typename T> void f(T); 

void bar() { 
f(42); 
} 

//f.h 
template<typename T> 
void f(T t) { 
} 

//f.cpp 
#include "f.h" 
template void f(int); 


$ nm bar.o 
       U _Z1fIiEvT_ 
0000000000000000 T _Z3barv 
+0

Pero, ¿aún se considera indefinido cuando bar.o está vinculado junto con f.o para crear un archivo ejecutable? Admito que no tengo experiencia práctica con '-wrap' para decir con certeza qué hará. –

+0

Aparentemente sí, de lo contrario, el enlazador no envolvería el símbolo con el prefijo '_wrap', ¿o estoy equivocado? El ejemplo anterior funciona cuando se usa con el nombre modificado ('_Z1fIiEvT_') como se muestra en el código al comienzo de esta publicación. – Mike

+0

Entonces, por supuesto, sí. Voy a modificar mi respuesta y referirme a su investigación. ¡Gracias! –

Cuestiones relacionadas