30

次のように宣言された関数があります。

template <typename T> 
T read();

次のように定義されます。

template <typename T>
T packetreader::read() {
    offset += sizeof(T);
    return *(T*)(buf+offset-sizeof(T)); 
}

ただし、 main() 関数で使用しようとすると:

packetreader reader;
reader.read<int>();

g++ から次のエラーが表示されます。

g++ -o main main.o packet.o
main.o: In function `main':
main.cpp:(.text+0xcc): undefined reference to `int packetreader::read<int>()'
collect2: ld returned 1 exit status
make: *** [main] Error 1

誰かが私を正しい方向に向けることができますか?

4

4 に答える 4

25

exportキーワードを使用する必要があります。ただし、G++ が適切にサポートされているとは思わないため、テンプレート関数の定義をヘッダーに含めて、翻訳ユニットが使用できるようにする必要があります。これは<int>、テンプレートの「バージョン」が作成されておらず、<typename T>「バージョン」のみが作成されているためです。

簡単な方法は#include.cpp ファイルです。ただし、他の関数が .cpp ファイルにある場合など、これにより問題が発生する可能性があります。また、コンパイル時間も増加する可能性があります。

きれいな方法は、テンプレート関数を独自の .cpp ファイルに移動し、それをヘッダーに含める、キーワードを使用しexportて個別にコンパイルすることです。

exportテンプレート関数の定義をヘッダー ファイルに入れようとする (そして完全に無視する) 必要がある理由の詳細については、こちらを参照してください。

于 2009-03-16T00:53:12.223 に答える
12

問題は、関数テンプレートが関数ではないことです。必要に応じて関数を作成するためのテンプレートです。

したがって、テンプレートが機能するためには、コンパイラは直観的に 2 つの情報を必要とします。それは、テンプレート自体と、テンプレートに代入される型です。これは、コンパイラが関数の存在を認識するとすぐに生成できる関数呼び出しとは異なります。関数が何をするかを知る必要はなく、関数が のように見えることvoid Frobnicate(int, float)や、その署名が何であるかを知る必要はありません。

関数テンプレートを定義せずに宣言すると、そのようなテンプレートが存在することだけがコンパイラに通知されますが、それがどのように見えるかは通知されません。コンパイラがそれをインスタンス化するには、それだけでは十分ではありません。完全な定義も表示できる必要があります。通常の解決策は、必要に応じて含めることができるヘッダーにテンプレート全体を配置することです。

于 2009-03-16T01:00:41.753 に答える
5

テンプレート関数のベスト プラクティスは、ヘッダー ファイルで定義することです。それらはコンパイル時に作成されるため、コンパイラはそうするために定義を持っている必要があります。

テンプレートがよりサポートされるようになると、これexportは当てはまりませんが、現時点ではまだほとんど使用できません。

于 2009-03-16T00:58:30.917 に答える
0

それらのコンパイラ サポート テンプレートは個別にコンパイルされていますか?

私が知っているように、一般的な方法は、ヘッダーファイルでテンプレート関数を宣言して実装することです

于 2009-03-16T01:01:08.180 に答える