明示的インスタンス生成 (C++ のみ)

コンパイラーに、テンプレートから定義をいつ生成するのかを明示的に指示できます。これは、明示的インスタンス化 と呼ばれます。 明示的インスタンス生成には、明示的インスタンス生成宣言および明示的インスタンス生成定義という 2 つのフォームが含まれます。

注: 変更の始まり IBM は、C++11 (承認前の呼称は C++0x) の、選定された機能をサポートしています。IBM® は、この新しい標準の機能の開発および実装を継続します。言語レベルの実装は、IBM によるこの標準の解釈に基づいています。新しい C++ 標準ライブラリーのサポートを含め、すべての C++11 機能を IBM が実装し終えるまで、リリースごとに実装が変更される可能性があります。IBM は、IBM による C++11 の新機能の実装に関し、ソース、バイナリー、またはリスト、および他のコンパイラー・インターフェースにおいて、以前のリリースとの互換性を維持するための試みは行いません。したがって、これらの新機能は安定的なプログラミング・インターフェースとしては利用しないでください。変更の終わり

C++11 C++11 のみの始まり。

明示的インスタンス生成宣言

変更の始まりC++11 標準では、明示的インスタンス生成宣言機能が導入されています。この機能を使用すると、テンプレート特殊化またはそのメンバーの暗黙のインスタンス生成を抑制できます。明示的インスタンス生成宣言を示すには、extern キーワードを使用します。ここでの extern の使用法は、ストレージ・クラス指定子の場合とは異なります。変更の終わり

構文図を読む構文図をスキップする
 明示的インスタンス生成宣言の構文 

>>-extern--template--template_declaration----------------------><

テンプレートの明示的インスタンス生成定義が、他の変換単位で存在するか、または後から同じファイル内に存在する場合は、テンプレート特殊化に対して明示的インスタンス生成宣言を指定できます。1 つの変換単位に明示的インスタンス生成定義が含まれる場合、他の変換単位は特殊化で複数回インスタンス生成を行うことなく、特殊化を使用できます。次の例は、このコンセプトを示しています。
//sample1.h:
template<typename T, T val>
union A{
T foo();
};
extern template union A<int, 55>;
template<class T, T val>
T A<T,val>::foo(void){
return val;
}
//sampleA.C"
#include "sample1.h"
template union A<int,55>;
//sampleB.C:
#include "sample1.h"
int main(void){
return A<int, 55>().foo();
}
sampleB.C は、sampleA.CA<int, 55>().foo() の明示的インスタンス生成定義を使用します。
関数またはクラスの明示的インスタンス生成宣言が宣言されているが、プログラム内に対応する明示的インスタンス生成定義が存在しない場合、コンパイラーはエラー・メッセージを出します。以下の例を参照してください。
// sample2.C
template <typename T, T val>
struct A{
    virtual T foo();
    virtual T bar();
}
extern template int A<int,55>:foo();
template <class T, T val>
T A<T,val>::foo(void){
    return val;
}
template <class T, T val>
T A<T,val>::bar(void){
    return val;
}
int main(void){
    return A<int,55>().bar();
}
明示的インスタンス生成宣言を使用する場合、以下の制約事項に注意してください。
  • 明示的インスタンス生成宣言では静的クラス・メンバーに命名できますが、静的関数には命名できません。これは、静的関数は他の変換単位では名前でアクセスできないためです。
  • 明示的インスタンス生成宣言は、インライン関数には影響を与えません。インライン関数は、インライン関数の明示的インスタンス生成宣言が存在する場合でも、依然として暗黙的にインスタンスが生成されますが、この場合には、インライン関数のアウトライン・コピーは生成されません。
  • クラスの明示的インスタンス生成宣言は、その各メンバーの明示的インスタンス生成宣言と等価ではありません。

C++11 C++11 のみの終わり。

明示的インスタンス生成定義

明示的インスタンス生成定義は、テンプレート特殊化またはそのメンバーの インスタンス生成です。
構文図を読む構文図をスキップする
 明示的インスタンス生成定義の構文 

>>-template--template_declaration------------------------------><

以下に、明示的インスタンス生成定義の例を示します。
template<class T> class Array { void mf(); };
template class Array<char>;      // explicit instantiation
template void Array<int>::mf();  // explicit instantiation

template<class T> void sort(Array<T>& v) { }
template void sort(Array<char>&); // explicit instantiation definition

namespace N {
template<class T> void f(T&) { }
}

template void N::f<int>(int&);
// The explicit instantiation definition is in namespace N.

int* p = 0;
template<class T> T g(T = &p);
template char g(char);                  // explicit instantiation definition

template <class T> class X {
private:
T v(T arg) { return arg; };
};

template int X<int>::v(int);    // explicit instantiation definition

template<class T> T g(T val) { return val;}
template<class T> void Array<T>::mf() { }
テンプレートの明示的インスタンス生成定義は、テンプレートを定義した場所と同じネーム・スペースにあります。

アクセス検査規則は、明示的インスタンス生成定義の引数には適用されません。 明示的インスタンス生成定義のテンプレート引数には、private 型または private オブジェクトを使用できます。この例では、メンバー関数が private で宣言されている場合でも、明示的インスタンス生成定義 template int X<int>::v(int) を使用できます。

テンプレートのインスタンスを明示的に生成する場合、コンパイラーは、デフォルトの引数を使用しません。 この例では、デフォルトの引数が型 int のアドレスである場合でも、明示的インスタンス生成定義 template char g(char) を使用できます。

C++11 C++11 のみの始まり。

明示的インスタンス生成定義およびインライン・ネーム・スペース定義

インライン・ネーム・スペース定義は、最初に inline キーワードを使用するネーム・スペース定義です。 インライン・ネーム・スペースのメンバーは、エンクロージング・ネーム・スペースのメンバーでもあるかのように、明示的にインスタンス化または特殊化できます。詳しくは、変更の始まりインライン名前空間定義 (C++11)変更の終わりを参照してください。

C++11 C++11 のみの終わり。