包装C ++模板函数

时间:2012-01-17 14:32:35

标签: c++ linker gnu function-templates

我尝试在GNU的链接器 wrap 选项的帮助下包装模板函数。代码如下所示:

// 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 _ 。你看到我犯过什么错误吗?

编辑:正如我所知,我在这里附加了 nm 的输出,以确保我没有对模板函数的错位名称进行任何错误:

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

2 个答案:

答案 0 :(得分:1)

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

  

- 涡卷=符号
  使用符号包装函数。任何未定义的符号引用都将解析为“_ wrap symbol”。对“_ 真实符号”的任何未定义引用都将解析为符号。

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


更新

  

我想因此无法包装模板函数?

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


更新2:我不确定,但迈克确认实验(参见他自己的答案和那里的评论)如果在目标文件中未定义符号,即使该目标文件与另一个对象链接在一起,包装也能正常工作包含符号定义的文件。太好了!

答案 1 :(得分:1)

评论很有帮助,但我认为没有必要将其拆分为可执行文件和(共享)库。关键是在调用源中具有模板函数的前向声明,并在单独的转换单元中使用所使用的类型来实例化模板函数。这保证了在bar.o中未定义f:

//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