包装C++模板函数

Mik*_*ike 6 c++ linker gnu function-templates

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

// 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();
}
Run Code Online (Sandbox Code Playgroud)

上面显示的代码与以下命令链接:

g++ -Xlinker -wrap=_Z1fIiEvT_ -o test test.o bar.o 
Run Code Online (Sandbox Code Playgroud)

不幸的是,这不起作用,并且始终调用原始函数f而不是我的包装版本__wrap__Z1fIiEvT_.你看到我犯过什么错误吗?

编辑:建议,我在这里附加nm的输出,以确保我没有使用模板函数的错位名称做任何错误:

$ g++ -c bar.cpp -o bar.o
$ nm bar.o
0000000000000000 W _Z1fIiEvT_
Run Code Online (Sandbox Code Playgroud)

Ale*_*nov 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:我不确定,但迈克通过实验证实(请参阅他自己的答案和那里的评论),如果目标文件中未定义符号,则换行有效,即使该目标文件与包含以下内容的另一个目标文件链接在一起符号定义。伟大的!