2012-01-17 105 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