テンプレートの明示的なインスタンス化について読んでいます:
template struct MyStruct<long>;
「かなり珍しい」と表現されていたのですが、どのような状況で役立つのでしょうか?
テンプレートの明示的なインスタンス化について読んでいます:
template struct MyStruct<long>;
「かなり珍しい」と表現されていたのですが、どのような状況で役立つのでしょうか?
ユースケースの1つは、エンドユーザーから定義を非表示にすることです。
tpl.h:
template<typename T>
void func(); // Declaration
tpl.cpp:
template<typename T>
void func()
{
// Definition
}
template void func<int>(); // explicit instantiation for int
template void func<double>(); // explicit instantiation for double
main.cpp
#include "tpl.h"
int main()
{
func<double>(); // OK
func<int>(); // OK
// func<char>(); - Linking ERROR
}
明示的なインスタンス化は、テンプレートライブラリの使用を最適化するように設計されており、ソースコード形式ではなくコンパイル済みのバイナリ形式で(主に使用される)テンプレートインスタンスの一部を提供します。これにより、エンドユーザーアプリケーションのコンパイルとリンクの時間が短縮されます。たとえばstd::basic_string<char>
、std::basic_string<wchar_t>
STLディストリビューションで明示的にインスタンス化できるため、各翻訳ユニットでのインスタンス化の作業を回避できます。
明示的なインスタンス化は、テンプレートの実装をカプセル化し、このテンプレートを既知のタイプのセットでのみ使用する場合にも役立ちます。この場合、テンプレート関数(freeまたはmembers)の宣言のみをヘッダーファイル(.h/.hpp
)に配置し、それらを変換単位(.cpp
)で定義できます。
例:
// numeric_vector.h
//////////////////////////////////////////////////
template <typename T> class numeric_vector
{
...
void sort();
};
// numeric_vector.cpp
//////////////////////////////////////////////////
// We know that it shall be used with doubles and ints only,
// so we explicitly instantiate it for doubles and ints
template class numeric_vector<int>;
template class numeric_vector<double>;
// Note that you could instantiate only specific
// members you need (functions and static data), not entire class:
template void numeric_vector<float>::sort();
template <typename T> void numeric_vector<T>::sort()
{
// Implementation
...
}
また、明示的なインスタンス化は、テンプレートからインスタンス化された型が必要な場合に役立ちますが、インスタンス化自体をトリガーしない構文構造内、たとえばVisualStudioのようなコンパイラ固有のメタ機能など__declspec(uuid)
です。
実装のカプセル化に使用できる別の手法(明示的な特殊化)との違いに注意してください。明示的な特殊化では、特殊化するタイプごとに特定の定義を提供する必要があります。明示的なインスタンス化を使用すると、単一のテンプレート定義が得られます。
明示的な特殊化を使用した同じ例を考えてみましょう。
例:
// numeric_vector.h
//////////////////////////////////////////////////
template <typename T> class numeric_vector
{
...
void sort();
};
template <> class numeric_vector<int>
{
...
void sort();
};
template <> class numeric_vector<double>
{
...
void sort();
};
// Specializing separate members is also allowed
template <> void numeric_vector<float>::sort();
// numeric_vector.cpp
//////////////////////////////////////////////////
void numeric_vector<int>::sort()
{
// Implementation for int
...
}
void numeric_vector<double>::sort()
{
// Implementation for double
...
}
void numeric_vector<float>::sort()
{
// Implementation for float
...
}
明示的な特殊化により、実装を非表示にすることができますが、これは、ご存知のように、テンプレートでは通常不可能です。
この手法は、ジオメトリを処理するライブラリで一度だけ見たことがあり、独自のベクトル クラスを提供していました。
だからあなたは使うことができます
lib::Vector<MyShape>
提供されたいくつかの基本的な機能lib::Vector
と基本的な実装を使用し、それらのクラス (すべてではなく一部) で使用した場合
lib::Vector<lib::Polygon>
明示的な特殊化を使用します。実装にアクセスすることはできませんが、裏でハードコアな最適化が行われているに違いありません。
ヘッダー ファイルでテンプレート関数を定義したくない場合は、別のソース ファイルで関数を定義し、明示的なテンプレートのインスタンス化を使用して、使用するすべてのバージョンをインスタンス化できます。次に、完全な定義ではなく、ヘッダー ファイルに前方宣言のみが必要です。