テンプレートはC++がパラメータ化多態性をサポートするためのツールです。テンプレートを使用すると、ユーザーはクラスまたは関数に対して一般的なパターンを宣言でき、クラス内の一部のデータメンバまたはメンバ関数のパラメータ、戻り値を任意の型にすることができます。
テンプレートは型をパラメータ化するツールです。
通常、関数テンプレートとクラステンプレートの2つの形式があります。
関数テンプレートは、パラメータの型だけが異なる関数を対象とします。
クラステンプレートは、データメンバとメンバ関数の型だけが異なるクラスを対象とします。
テンプレートを使用する目的は、プログラマが型に依存しないコードを書けるようにすることです。例えば、2つのint型を交換するswap関数を書いた場合、この関数はint型にしか対応できず、doubleやcharなどの型には対応できません。これらの型の交換を実現するには、別のswap関数を書き直す必要があります。テンプレートを使用する目的は、プログラムの実装を型に依存しないようにすることです。例えば、swapテンプレート関数はint型の交換もdouble型の交換も実現できます。テンプレートは関数とクラスに適用できます。以下でそれぞれ説明します。
注意:テンプレートの宣言または定義は、グローバル、名前空間、またはクラスのスコープ内でのみ行えます。つまり、ローカルスコープや関数内では行えません。例えば、main関数内でテンプレートを宣言または定義することはできません。
一、関数テンプレートの一般形式
1、関数テンプレートの形式:
template <class 形参名,class 形参名,......> 返回类型 函数名(参数列表)
{
函数体
}
ここでtemplateとclassはキーワードです。classはtypenameキーワードで置き換えることができます。ここではtypenameとclassに違いはありません。<>括弧内のパラメータをテンプレート仮引数と呼びます。テンプレート仮引数は関数仮引数とよく似ていますが、テンプレート仮引数を空にすることはできません。テンプレート関数を宣言すると、テンプレート関数の仮引数名を使用してクラス内のメンバ変数やメンバ関数を宣言できます。つまり、その関数内で組み込み型を使用できる場所ならどこでもテンプレート仮引数名を使用できます。テンプレート仮引数は、そのテンプレート関数を呼び出すときに提供されるテンプレート実引数によって初期化する必要があります。コンパイラが実際のテンプレート実引数の型を決定すると、関数テンプレートのインスタンスをインスタンス化したと呼びます。例えば、swapテンプレート関数の形式は次のとおりです:
template <class T> void swap(T& a, T& b){},
このようなテンプレート関数を呼び出すとき、型Tは呼び出し時の型に置き換えられます。例えばswap(a,b)ここでaとbであるint型の場合、テンプレート関数swap内の仮引数はTによって置き換えられ、intテンプレート関数は次のようになります:swap(int &a, int &b)。一方、swap(c,d)ここでcとdであるdouble型の場合、テンプレート関数は次のように置き換えられます:swap(double &a, double &b)これにより、関数の実装が型に依存しないコードを実現できます。
2、注意:関数テンプレートに関しては、次のような呼び出しは存在しません:h(int,int)このような呼び出しはありません。関数呼び出しの引数でテンプレート仮引数の型を指定することはできません。関数テンプレートの呼び出しは、実引数推論を使用して行うべきです。つまり、次のような呼び出しのみ可能です: h(2,3)このような呼び出し、またはint a, b; h(a,b)。
関数テンプレートの具体例は後述します!
二、クラステンプレートの一般形式
1、クラステンプレートの形式は次のとおりです:
template<class 形参名,class 形参名,…> class 类名
{ ... };
クラステンプレートと関数テンプレートはどちらもtemplateで始まり、その後ろにテンプレート仮引数リストが続きます。テンプレート仮引数は空にできません。クラステンプレートを宣言すると、クラステンプレートの仮引数名を使用してクラス内のメンバ変数とメンバ関数を宣言できます。つまり、クラス内で組み込み型を使用できる場所ならどこでもテンプレート仮引数名を使用して宣言できます。例えば
template<class T> class A{public: T a; T b; T hy(T c, T &d);};
クラスA内に、型がTの2つのメンバ変数aとbを宣言し、戻り値の型がTで、2つの引数の型がTである関数hyも宣言しています。
2、クラステンプレートオブジェクトの作成:例えば、テンプレートクラスAがある場合、クラステンプレートを使用してオブジェクトを作成する方法は次のとおりです:A<int> m;クラスAの後ろに<>山括弧を付け、その中に対応する型を記入します。これにより、クラスA内でテンプレート仮引数を使用しているすべての場所がintによって置き換えられます。クラステンプレートに2つのテンプレート仮引数がある場合、オブジェクトを作成する方法は次のとおりです:A<int, double> m;型の間はカンマで区切ります。
3、クラステンプレートの場合、テンプレート仮引数の型はクラス名の後ろの山括弧内で明示的に指定する必要があります。例えばA<2> m;この方法でテンプレート仮引数をintに設定するのは誤りです(コンパイルエラー:error C2079: 'a' uses undefined class 'A<int>'),クラステンプレートの仮引数には実引数推論の問題はありません。つまり、整数値2をint型としてテンプレート仮引数に推論して渡すことはできません。クラステンプレートの仮引数をint型に設定するには、次のように指定する必要があります:A<int> m。
4、クラステンプレートの外部でメンバ関数を定義する方法は次のとおりです:
template<模板形参列表> 函数返回类型 类名<模板形参名>::函数名(参数列表){函数体},
例えば、2つのテンプレート仮引数T1、T2を持つクラスAにvoid h()関数が含まれている場合、その関数を定義する構文は次のとおりです:
template<class T1,class T2> void A<T1,T2>::h(){}。
注意:クラスの外でクラスのメンバを定義する場合、templateの後ろのテンプレート仮引数は、定義しようとするクラスのテンプレート仮引数と一致している必要があります。
5、再度注意を促します:テンプレートの宣言または定義は、グローバル、名前空間、またはクラスのスコープ内でのみ行えます。つまり、ローカルスコープや関数内では行えません。例えば、main関数内でテンプレートを宣言または定義することはできません。
三、テンプレートの仮引数
テンプレート仮引数には3つの型があります:型仮引数、非型仮引数、テンプレート仮引数です。
1、型仮引数
1.1、型テンプレート仮引数:型仮引数は、キーワードclassまたはtypenameの後ろに指定子を続けて構成されます。例えばtemplate<class T> void h(T a){};ここでTは型仮引数であり、型仮引数の名前はユーザー自身が決定します。テンプレート仮引数は未知の型を表します。テンプレート型仮引数は、型指定子としてテンプレート内のどこでも使用でき、組み込み型指定子やクラス型指定子とまったく同じように使用できます。つまり、戻り値の型の指定や変数の宣言などに使用できます。
著者オリジナル版:1.2、同じテンプレート型仮引数に2つの異なる型を指定することはできません。例えばtemplate<class T>void h(T a, T b){},文の呼び出しh(2, 3.2)はエラーになります。なぜなら、その文は同じテンプレート仮引数Tに2つの型を指定しているからです。最初の実引数2はテンプレート仮引数Tをintに指定し、2番目の実引数3.2はテンプレート仮引数をdoubleに指定しています。2つの型の仮引数が一致しないため、エラーになります。(関数テンプレートに関するもの)
著者オリジナル版:1.2は関数テンプレートに対しては正しいですが、クラステンプレートを無視しています。以下でクラステンプレートの場合を補足します。
筆者による1.2補足版(クラステンプレート向け)、クラスオブジェクトを次のように宣言した場合:A<int> a、例えばtemplate<class T>T g(T a, T b){}、文の呼び出しa.g(2, 3.2)はコンパイル時にはエラーになりませんが、警告が出ます。なぜなら、クラスオブジェクトを宣言するときに既にTをint型に変換しており、2番目の実引数3.2はテンプレート仮引数をdoubleに指定しているため、実行時に3.2が3に強制型変換されます。クラスのオブジェクトを次のように宣言した場合:A<double> a、このときは上記の警告はありません。なぜならint到doubleは自動型変換だからです。
デモ例1:
TemplateDemo.h
コンパイル結果:
--------------------Configuration: TemplateDemo - Win32 Debug-------------------- Compiling... TemplateDemo.cpp G:\C++\CDaima\TemplateDemo\TemplateDemo.cpp(12) : warning C4244: 'argument' : conversion from 'const double' to 'int', possible loss of data TemplateDemo.obj - 0 error(s), 1 warning(s)
実行結果:5
上記のテスト例からわかるように、著者のオリジナル版ほど厳密ではありません!ここは筆者の個人的なテスト結果に過ぎません!皆さんには事実を重んじる態度で、ご自身で検証していただきたいと思います!
2、非型仮引数
2.1、非型テンプレート仮引数:テンプレートの非型仮引数は、組み込み型の仮引数です。例えばtemplate<class T, int a> class B{};ここでint aは非型テンプレート仮引数です。
2.2、非型仮引数はテンプレート定義の内部では定数値です。つまり、非型仮引数はテンプレートの内部では定数です。
2.3、 非型テンプレートの仮引数は、整数型、ポインタ、参照のみです。、double、String、String **のような型は許可されません。ただし、double &,double *,オブジェクトの参照またはポインタは正しいです。
2.4、 非型テンプレート仮引数に渡す実引数は定数式でなければなりません。つまり、コンパイル時に結果を計算できなければなりません。
2.5、注意:ローカルオブジェクト、ローカル変数、ローカルオブジェクトのアドレス、ローカル変数のアドレスはすべて定数式ではないため、非型テンプレート仮引数の実引数として使用できません。グローバルポインタ型、グローバル変数、グローバルオブジェクトも定数式ではないため、非型テンプレート仮引数の実引数として使用できません。
2.6、 ; A<b> m; すなわち配列からポインタへの変換です。。
2.7 、sizeof式の結果が定数式である場合も、非型テンプレート仮引数の実引数として使用できます。
2.8、テンプレートの仮引数が整数型の場合、そのテンプレートを呼び出す際の実引数は整数型でなければならず、かつコンパイル期間中に定数である必要があります。例えばtemplate <class T, int a> class A{};もしint b があり、このとき A<int, b> m;はエラーになります。なぜならbb は定数ではないからです。もしconst int b の場合、A<int, b> m; は正しいです。なぜならこのときbb は定数だからです。
2.9 、非型仮引数は通常、関数テンプレート内では使用すべきではありません。、例えば関数テンプレートがあると、template<class T, int a> void h(T b){}これを使用してh(2){'translated_text': '{'translated_text': '呼び出すと、非型仮引数 a に対して実引数を推論できないというエラーが発生します。このようなテンプレート関数は、明示的テンプレート実引数を使用して解決できます。例えば、h<int, 3>(2) のようにすると、非型仮引数 a が整数 3 に設定されます。明示的テンプレート実引数については後で説明します。'}'}
2.10、非型テンプレート仮引数と実引数の間で許可される変換
1、配列からポインタへ、関数からポインタへの変換が許可されます。例:template <int *a> class A{}; int b
2、const修飾子の変換。例:template<const int *a> class A{}; int b; A<&b> m; すなわち int * から const int * への変換です。
3、昇格変換。例:template<int a> class A{}; const short b=2; A<b> m; すなわち short から int への昇格変換です。
4、整数値変換。例:template<unsigned int a> class A{}; A<3> m; すなわち int から unsigned int への変換です。
5、通常の変換。
非型仮引数のデモ例1:
ユーザー自身がスタックのサイズを指定し、スタックに関する操作を実装します。
TemplateDemo.h
TemplateDemo.cpp

非型仮引数のデモ例2:
TemplateDemo01.h
TemplateDemo01.cpp
実行結果:-1
TemplateDemo01.cpp
実行結果:1
TemplateDemo01.h
TempalteDemo01.cpp
非型仮引数のデモ例3:
TemplateDemo02.cpp
実行結果:

cout<<max<int>(2.1,2.2)<<endl; //显示指定的模板参数,会将函数函数直接转换为int。
この文では警告が発生します:
--------------------Configuration: TemplateDemo02 - Win32 Debug-------------------- Compiling... TemplateDemo02.cpp G:\C++\CDaima\TemplateDemo02\TemplateDemo02.cpp(11) : warning C4244: 'argument' : conversion from 'const double' to 'const int', possible loss of data G:\C++\CDaima\TemplateDemo02\TemplateDemo02.cpp(11) : warning C4244: 'argument' : conversion from 'const double' to 'const int', possible loss of data TemplateDemo02.obj - 0 error(s), 2 warning(s)
四、クラステンプレートのデフォルトテンプレート型仮引数
1、クラステンプレートの型仮引数にはデフォルト値を指定できますが、関数テンプレートの型仮引数にはデフォルト値を指定できません。関数テンプレートとクラステンプレートはどちらも、テンプレートの非型仮引数にデフォルト値を指定できます。
2、クラステンプレートの型仮引数のデフォルト値の形式は次のとおりです:template<class T1, class T2=int> class A{};2番目のテンプレート型仮引数にT2提供しますint型のデフォルト値を。
3、クラステンプレートの型仮引数のデフォルト値は関数のデフォルト引数と同じです。複数の型仮引数がある場合、最初の仮引数にデフォルト値を設定した後のすべてのテンプレート仮引数にもデフォルト値を設定する必要があります。例えばtemplate<class T1=int, class T2>class A{};これはエラーです。なぜならT1デフォルト値を指定したが、T2設定されていないからです。
4、クラステンプレートの外部でクラスのメンバーを定義する場合templatetemplate の後の仮引数リストではデフォルトの仮引数型を省略する必要があります。例えばtemplate<class T1, class T2=int> class A{public: void h();}; 定義方法は次のとおりです。template<class T1,class T2> void A<T1,T2>::h(){}。
クラステンプレートの型仮引数を定義します:
デモ実例1:
TemplateDemo.h
TemplateDemo.cpp
実行結果:5
クラステンプレートのデフォルトテンプレート型仮引数の例1:
TemplateDemo03.h
TemplateDemo03.cpp
実行結果:2
クラステンプレートの外部でクラスのメンバーを定義する場合、template の後の仮引数リストではデフォルトの仮引数型を省略する必要があります。省略しない場合、コンパイルエラーにはならず、警告が発生します:
--------------------Configuration: TemplateDemo03 - Win32 Debug-------------------- Compiling... TemplateDemo03.cpp g:\c++\cdaima\templatedemo03\templatedemo03.h(12) : warning C4519: default template arguments are only allowed on a class template; ignored TemplateDemo03.obj - 0 error(s), 1 warning(s)
原作者:クラステンプレートの型仮引数のデフォルト値は関数のデフォルト引数と同じです。複数の型仮引数がある場合、最初の仮引数にデフォルト値を設定した後のすべてのテンプレート仮引数にもデフォルト値を設定する必要があります。例えばtemplate<class T1=int, class T2>class A{};これはエラーです。なぜならT1デフォルト値を指定したが、T2設定されていないからです。
クラステンプレートのデフォルトテンプレート型仮引数の例2:
TemplateDemo03.h
TemplateDemo03.cpp
実行結果:9
TemplateDemo03.h
TemplateDemo03.cpp
コンパイルエラー:
--------------------Configuration: TemplateDemo03 - Win32 Debug-------------------- Compiling... TemplateDemo03.cpp g:\c++\cdaima\templatedemo03\templatedemo03.h(12) : error C2244: 'CeilDemo<T1,T2,T3>::ceil' : unable to resolve function overload g:\c++\cdaima\templatedemo03\templatedemo03.cpp(6) : error C2065: 'cd' : undeclared identifier g:\c++\cdaima\templatedemo03\templatedemo03.cpp(6) : error C2228: left of '.ceil' must have class/struct/union type Error executing cl.exe. TemplateDemo03.obj - 3 error(s), 0 warning(s)
上の例からわかるように、T2とT3をdouble型に定義しようとするとエラーが発生します(T1はデフォルトでint型に定義されています)。では、著者の言うとおりにT2とT3もデフォルト値のdoubleに設定した場合、エラーは発生しないのでしょうか?次の例を見てください:
クラステンプレートのデフォルトテンプレート型仮引数の例4:
TemplateDemo03.h
TemplateDemo03.cpp
コンパイルエラー:
--------------------Configuration: TemplateDemo03 - Win32 Debug-------------------- Compiling... TemplateDemo03.cpp g:\c++\cdaima\templatedemo03\templatedemo03.h(12) : error C2244: 'CeilDemo<T1,T2,T3>::ceil' : unable to resolve function overload g:\c++\cdaima\templatedemo03\templatedemo03.cpp(6) : error C2065: 'cd' : undeclared identifier g:\c++\cdaima\templatedemo03\templatedemo03.cpp(6) : error C2228: left of '.ceil' must have class/struct/union type Error executing cl.exe. TemplateDemo03.obj - 3 error(s), 0 warning(s)
結果からわかるように、前の例と同じエラーです。この実例から次のようにまとめられます:クラステンプレートに複数の型仮引数がある場合、型仮引数のデフォルト値を使用するなら、できるだけパラメータリストの末尾に配置し、デフォルトのパラメータ型は同じでなければなりません。最初の仮引数にデフォルト値を設定した場合、その後のすべてのテンプレート仮引数にも最初の仮引数と同じ型のデフォルト値を設定する必要があります。(声明:私自身もC++を始めたばかりで、以上は私が実例のデモを通して原作者に提示したいくつかの疑問にすぎません。私の例には不十分な点があるかもしれません。どうか達人の方々にご教示いただき、このブログを共に改善し、私のような初心者に学習の場を提供していただければ幸いです!)
次に、「関数テンプレートの型仮引数にデフォルト値を指定できない」ことを検証します:
クラステンプレートのデフォルトテンプレート型仮引数の例5:
TemplateDemo04.cpp
コンパイルエラー:
--------------------Configuration: TemplateDemo04 - Win32 Debug-------------------- Compiling... TemplateDemo04.cpp g:\c++\cdaima\templatedemo04\templatedemo04.cpp(4) : error C2062: type 'int' unexpected Error executing cl.exe. TemplateDemo04.obj - 1 error(s), 0 warning(s)
変更後の TemplateDemo.cpp
TemplateDemo.cpp
実行結果:261.1
原作者のデモ例は次のとおりです:
クラステンプレート非型仮引数の例
原文アドレス:
https://www.cnblogs.com/gw811/archive/2012/10/25/2738929.html
http://www.cnblogs.com/gw811/archive/2012/10/25/2736224.html