テンプレートクラスを使用して共有ライブラリにリンクしようとしていますが、「未定義のシンボル」エラーが発生します。この問題を約20行のコードに要約しました。
shared.h
template <class Type> class myclass {
Type x;
public:
myclass() { x=0; }
void setx(Type y);
Type getx();
};
shared.cpp
#include "shared.h"
template <class Type> void myclass<Type>::setx(Type y) { x = y; }
template <class Type> Type myclass<Type>::getx() { return x; }
main.cpp
#include <iostream>
#include "shared.h"
using namespace std;
int main(int argc, char *argv[]) {
myclass<int> m;
cout << m.getx() << endl;
m.setx(10);
cout << m.getx() << endl;
return 0;
}
これは私がライブラリをコンパイルする方法です:
g++ -fPIC -c shared.cpp -o shared.o
g++ -dynamiclib -Wl,-dylib_install_name -Wl,libshared.dylib -o libshared.dylib shared.o
そしてメインプログラム:
g++ -c main.cpp
g++ -o main main.o -L. -lshared
次のエラーが発生するだけです。
Undefined symbols:
"myclass<int>::getx()", referenced from:
_main in main.o
_main in main.o
"myclass<int>::setx(int)", referenced from:
_main in main.o
shared.h/cpp
の「テンプレート」を削除して、「int」に置き換えると、すべて正常に動作します。また、テンプレートクラスのコードをmain.cpp
に直接コピーして貼り付け、共有ライブラリにリンクしない場合でも、すべてが機能します。
このようなテンプレートクラスを共有ライブラリで機能させるにはどうすればよいですか?
MacOS 10.5とGCC 4.0.1を使用しています。
他の回答に加えて、テンプレートクラスを明示的にインスタンス化できます。これは、テンプレートパラメータで想定されるタイプを事前に知っている場合にのみ役立ちます。ライブラリ内のこれらすべてのタイプでテンプレートをインスタンス化します。
あなたの例をコンパイルするには、次のコードをshared.cppの最後に追加するだけです:
// Instantiate myclass for the supported template type parameters
template class myclass<int>;
template class myclass<long>;
これにより、Type = intでテンプレートがインスタンス化され、インスタンス化されたコードが共有ライブラリに配置されます。必要なすべてのタイプについて、必要な数の明示的なインスタンス化を追加します。
繰り返しますが、任意のTypeパラメータを使用してテンプレートをインスタンス化できるようにする場合は、must定義をヘッダーファイルに追加して、インスタンス化するときにコンパイラがテンプレートのソースコードを認識できるようにします。他のコンパイル単位。
テンプレート関数の定義は、ヘッダーファイルに存在する必要があります。定義をshared.cppからshared.hに移動します。
したがって、これを共有ライブラリにコンパイルしてからリンクすることはできません。それはちょうどそのように機能しません。
ヘッダーファイルにもテンプレートクラスの実装を含める必要があります。これはC++のテンプレートの制約です。したがって、メインからshared.cppをインクルードする(#include)か、shared.hのshared.cppからコードを移動するだけです。
コンパイラーはテンプレートのすべてのコードを参照する必要があるため、使用する実際のタイプに適したコードを生成できます。したがって、すべてのコードを.hに配置する必要があります。ファイル。