テンプレートのエクスポートとインポート
C++ の仕様:インデックス への移動
テンプレート関数やテンプレート クラスは、ダイナミック リンク ライブラリ(共有ライブラリ)と実行可能ファイルのどちらでも使用できるように十分柔軟に宣言する必要があります。同じテンプレート宣言をインポートまたはエクスポートとして、あるいは修飾子なしで使用できる必要があります。十分に柔軟な宣言にするには、ヘッダー ファイルのテンプレート宣言で __export 修飾子や __import 修飾子を使用しないでください。それにより、インスタンス化をどう使用するかに応じて、インスタンス化の時点で適切な修飾子を適用することができます。
次の手順は、テンプレートのエクスポートおよびインポートの例を示しています。ソース コードは 3 つのファイルで構成されます。ヘッダー ファイルを使用して、ダイナミック リンク ライブラリにコードが生成されます。
- エクスポート可能/インポート可能なテンプレート宣言
- ヘッダー ファイルには、テンプレート クラスおよびテンプレート関数の宣言がすべて含まれています。テンプレートのエクスポート/インポート バージョンは、コンパイル時に適切なマクロを定義することによりインスタンス化することができます。
- エクスポート可能なテンプレートのコンパイル
- ダイナミック リンク ライブラリのソース コードを記述します。コンパイルすると、このライブラリには、テンプレートの再利用可能なエクスポート コードが含まれています。
- ImportTemplates の使用
- これで、テンプレートを使用する呼び出し側関数を記述できます。この実行可能ファイルはダイナミック リンク ライブラリにリンクされます。ヘッダー ファイルで宣言されておらず main 関数でインスタンス化されるオブジェクトの場合のみ、コンパイラで新しいコードが生成されます。新しくインスタンス化されたオブジェクトのコードは、main.obj ファイルに書き込まれます。
エクスポートされるクラスのテンプレート メンバの明示的なインスタンス化とエクスポート
テンプレート メンバ関数を含んだクラスを(__declspec(dllexport) 指令か PACKAGE マクロをそれぞれ使って)DLL またはパッケージからエクスポートする場合、これらのメンバは明示的にインスタンス化されエクスポートされる必要があります。そうでないと、エクスポートされたクラスのコンシューマで、テンプレート メンバに関する未解決の外部参照エラーが発生するおそれがあります。
例:
mypackage.h:
#define PACKAGE __declspec(package)
class PACKAGE X
{
public:
int foo();
template<typename T>
int bar(T *p)
{
return *p;
}
};
mypackage.cpp:
#include "mypackage.h"
int X::foo()
{
return 7;
}
上記は C++ パッケージに存在しています。
次のアプリケーションで bar メンバを呼び出すと、未解決の外部シンボル参照エラーが発生します。
myapp.cpp:
#include "mypackage.h"
int g = 6;
int main()
{
X x;
x.foo();
return x.bar(&g);
}
Error: Error: Unresolved external 'int X::bar<int>(int*)' referenced from C:\USERS\ADMIN_000\APPDATA\LOCAL\TEMP\MYAPP-233656.O
このエラーを解決するには、次の行を mypackage.cpp に追加します。
template PACKAGE int X::bar<int>(int*);
追加された行では、myapp.cpp ソースで使用されるメンバ テンプレートを明示的にインスタンス化しエクスポートしています。