2012-01-17 108 views
6

我试着用GNU的链接器包装选项来包装模板函数。代码如下所示:包装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(); 
} 

上面显示的代码是用下面的命令链接:

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

不幸的是,这并不工作,始终原有功能˚F被调用,而不是我的包装版本__wrap__Z1fIiEvT_。你看到我犯过的错误吗?

编辑:诚如,我附上纳米这里输出,以确保我没有做任何的失误与模板函数的重整名称:

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

仔细检查您是否使用'nm'或类似工具调用了正确的装饰函数。将相关输出添加到问题中可能会有所帮助。 – uesp 2012-01-17 15:57:00

+0

不应该f(42);是f (42)? – 2012-01-20 18:34:54

+1

@ Fire-Dragon-DoL - 模板函数将从参数中推断它们的参数类型,并且由于int是另外一个未修饰的整数文字的类型,所以这可以正常工作。如果f是一个类,那么模板参数需要是明确的。 – Marc 2012-01-20 18:47:40

回答

1

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

--wrap = symbol
对符号使用包装函数。任何未定义的符号参考将被解析为“_ 包装符号”。任何对“_ real symbol”未定义的引用将被解析为符号。

我认为单词“未定义”可能是这里的关键。您感兴趣的符号无疑在bar.o中定义,并且nm输出会确认它,因为未定义的符号标有“U”而不是“W”。


更新:

我猜,因此它是不可能来包装模板的功能呢?

我认为它更多地取决于函数定义(或实例化)的位置,以及此定义是否可用于链接器。在你的情况下,如果你在bar.cpp中定义了一个非模板函数,那么它的结果是一样的。 即使你在bar.cpp中定义了这个函数,但是在main.cpp中使用了它,我想它会是一样的,尽管不能完全确定(你可以试试看)。 我相信,如果你将bar.cpp和main.cpp链接到不同的模块(一个共享库和一个可执行文件),那么你将能够从main.cpp中使用的bar.cpp中包装一个函数,无论如何无论是模板还是不是。


更新2:我不知道,但我是迈克证实实验(看他自己的答案,有评论)如果符号在目标文件未被定义的,包装的工作,即使该目标文件链接以及另一个包含符号定义的目标文件。大!

+0

你是对的。因为编译器为实例化的函数模板生成代码,所以它不再是未定义的符号,因此链接器不会将其包装为“_wrap_symbol”。我想这是不可能的包装模板功能? – Mike 2012-01-19 08:46:53

1

评论有帮助,但我不认为有必要将它分为可执行文件和(共享)库。关键是要对调用原点中的模板函数进行前向声明,并在单独的翻译单元中将使用的类型实例化为模板函数。这保证了f在bar中是未定义的。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

但是,当bar.o与f.o链接在一起以创建可执行文件时,它仍然被认为是未定义的吗?我承认我没有'-wrap'的实际经验来说明它会做什么。 – 2012-01-24 12:41:32

+0

显然是的,否则链接器不会用'_wrap'前缀来包装符号,还是我错了?上面给出的例子在与本文开头的代码所示的mangled包装名称('_Z1fIiEvT_')一起使用时有效。 – Mike 2012-01-24 14:14:08

+0

当然,是的。我会修改我的答案并提及你的调查。谢谢! – 2012-01-24 15:04:38