6

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();
}

上記のコードは、次のコマンドにリンクされています。

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

残念ながら、これは機能せず、ラップされたバージョン__wrap__Z1fIiEvT_の代わりに常に元の関数fが呼び出されます。私が犯した間違いはありますか?

編集: アドバイスどおり、ここにnmの出力を追加して、テンプレート関数のマングル名に誤りがないことを確認します。

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

2 に答える 2

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
于 2012-01-24T10:20:55.447 に答える
1

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

--wrap=symbol シンボル
のラッパー関数を使用します。シンボルへの未定義の参照は、「_ラップシンボル」に解決されます。「_ real symbol 」への未定義の参照はすべて、シンボルに解決されます。

ここで「未定義」という言葉が鍵になると思います。関心のあるシンボルは確かに bar.o で定義されておりnm、未定義のシンボルは「W」ではなく「U」でマークされているため、出力はそれを確認します。


アップデート:

したがって、テンプレート関数をラップすることはできないと思いますか?

関数が定義されている(またはインスタンス化されている)場所と、この定義がリンカーで利用できるかどうかに大きく依存すると思います。あなたの場合、使用されている bar.cpp で非テンプレート関数を定義した場合、結果は同じになります。bar.cpp で関数を定義し、main.cpp で使用した場合でも、完全にはわかりませんが同じであると思います (試してみてください)。また、bar.cpp と main.cpp を別のモジュール (共有ライブラリと実行可能ファイル) にリンクすると、main.cpp で使用される bar.cpp から関数をラップできると確信しています。それはテンプレートかどうかです。


更新 2: 確かではありませんでしたが、Mike は実験 (彼自身の回答とそこのコメントを参照) で、オブジェクト ファイルでシンボルが定義されていない場合、そのオブジェクト ファイルが別のオブジェクト ファイルと一緒にリンクされていても、ラッピングが機能することを確認しました。シンボル定義。すごい!

于 2012-01-18T18:14:09.073 に答える