テンプレートは、ジェネリックプログラミングを実現するための基礎です。ジェネリックプログラミングとは、型とは関係のない論理コードを記述することを指し、再利用を実現する手段です。
テンプレートは、関数テンプレート、クラステンプレートに分けることができます。
関数テンプレート
概念
関数テンプレートは関数のファミリーを表します。関数テンプレートはタイプとは関係ありません。使用時にパラメーター化され、実際のパラメーターのタイプに従って関数の特定のタイプバージョンが生成されます。
関数テンプレート形式
template<typename T1,typename T2,……,typename Tn>
返回值类型 函数名(形参列表){
函数体}
といった:
template<typename T>
void Swap(T& left,T& right){
T tmp = left;
left = right;
right = tmp;
}//一个可以实现交换功能的函数模板
【注意】: 代わりtypename
に使用class
することもできます
関数テンプレートの原理
関数テンプレートは、コンパイラが特定の種類の関数を生成するための型であり、関数自体ではありません。
コンパイラーのコンパイル段階で、特定の型の関数を生成するために関数テンプレートを使用する必要がある場合、コンパイラーは実際のパラメーター型を差し引いて着信型Tを判別し、次に特殊な関数を生成します。 T型を処理します。
といった:
double a = 3.14, b = 6.28;
int x = 1,y = 2;
char r = 'a', t = 'v';
Swap(a,b);
Swap(x,y);
Swap(r,t);
コードSwap
内の関数テンプレートにより、3つの呼び出しで異なるタイプのデータが渡され、コンパイラーはステージで各受信データのタイプを推測し、それぞれの対応する関数を生成します。
上記のコードには、コンパイル段階でさらに3つの関数があります。
void Swap(double& left,double& right){
T tmp = left;
left = right;
right = tmp;
}
void Swap(int& left,int& right){
int tmp = left;
left = right;
right = tmp;
}
void Swap(char& left,char& right){
char tmp = left;
left = right;
right = tmp;
}
これらの3つの関数は、それぞれSwap関数の3つの呼び出しに対応します。関数テンプレートのみを記述しましたが、最終的なコードでは、さまざまなタイプの実際のパラメーターが渡され、さらに多くの関数が生成されます。つまり、テンプレートを使用するコードには、コードの膨張の問題があります。
ただし、異なる種類のデータに対して同じ関数を実現するために関数テンプレートは必要ないと思います。関数のオーバーロードによってのみ関数を実装できるようであり、それでも多くの関数を作成する必要があります。テンプレートを使用すると、開発者は同じ関数や異なるタイプの関数を繰り返し作成する必要がなくなります。これにより、開発者にとってほとんど重要ではない非効率的で避けられない作業コンテンツがある程度削減され、作業効率が向上します。テンプレートを使用するコードの展開に問題があったとしても、テンプレートを使用しないところまでしか展開されないようです。これは容認できない問題ではありません。
関数テンプレートのインスタンス化
コンパイラが入力引数のタイプを推測し、さまざまなタイプに対応する関数を生成するプロセスは、関数テンプレートのインスタンス化と呼ばれます。テンプレートのインスタンス化は、暗黙的なインスタンス化と明示的なインスタンス化に分けることができます。
暗黙のインスタンス化
暗黙的なインスタンス化とは、開発者が渡された引数のタイプをコンパイラに通知せず、渡された引数のタイプに基づいて生成する関数の種類をコンパイラに推測させることを意味します。以下のように、どのタイプの引数が渡されるかをコンパイラーに通知しません。
template<typename T>
void Swap(T& left,T& right){
T tmp = left;
left = right;
right = tmp;
}//一个可以实现交换功能的函数模板
int main(){
double a = 3.14, b = 6.28;
Swap(a,b);//隐式实例化
return 0;
}
明示的なインスタンス化
インスタンス化を表示するには、次のように、関数名に<>
実際のパラメータータイプを入力するだけで済みます
。
Swap<double>(a,b);//显式实例化
個人的には、関数テンプレートを使用するときは明示的なインスタンス化を使用して、自分のコードを把握し、他の人が読みやすくする必要があると感じています。
テンプレートパラメータのマッチング原則
一般的に、非テンプレート関数と関数を完成させることができるテンプレート関数の両方が存在する場合、コンパイラーが関数を定義する方法を決定するのに役立つ戦略があります。
土語では、指定された関数を完了することができる関数の種類がたくさんあります。この関数の山にある関数コンパイラの中には、何もする必要がないものがあります。呼び出された関数のパラメータリストと完全に一致します。暗黙の型変換が必要なものもあります。開発者によって指定された型変換があります。現時点では、関数を完成させたい場合、多くのオプションがあります。結果のエラーを回避し、コンパイラーが左右にジャンプするのを防ぐために、コンパイラーが呼び出される関数を選択するのに役立つ選択戦略があります。 。
調整の選択戦略は次のとおりです(優先順位は高いものから低いものへと配置され
ます)。1。完全一致:関数テンプレートと非テンプレート関数が同時に存在し、指定された関数を完了することができ、タイプが競合しません(好ましい非テンプレート関数を使用)
2.アップグレード変換char
してshort
自動変換int
、flaot
に自動変換double
)
3.標準変換(int
CHARに、long
転送にdouble
)
そのようなクラス宣言で定義された変換として前記ユーザ定義の変換、
テンプレートの制限
次のテンプレート関数があるとします。
template<typename T>
void f(T a,T b){
//函数体
}
一般的に言えば、関数にはいくつかの操作があります。
といった:
a = b
場合T
組み込みデータ型、この割り当ては我々の期待に沿ったものになります。
しかしT
、配列/文字列/非構築タイプの構造などであるため、結果はおそらく私たちの期待を満たしていません。
もう一つの例:
if(a>b)
場合はT
配列で、a>b
配列の比較a
とb
アドレスレベル、これは我々が望むものはおそらくではありません。
つまり、テンプレート関数は特定のタイプを処理できない場合があります。
すべてに2つの側面があることを覚えておく必要があります!絶対に良いものも、絶対に悪いものもありません。
クラステンプレート
クラステンプレート形式
template<class T1,class T2,……,class Tn>
class 类模板名
{
//类内成员定义
}
【注意】クラステンプレート内のクラスのメンバーをクラス外で定義する場合は、テンプレートパラメータリストを追加する必要があります。
クラステンプレートのインスタンス化
関数テンプレートのインスタンス化とは異なり、クラステンプレートのインスタンス化は、クラステンプレート名の後に追加する必要があり<>
ます<>
。次に、インスタンス化された型をに配置します。つまり、明示的にインスタンス化する必要があります。
同じ説明がクラステンプレートにも当てはまります。クラステンプレートはクラスではありません。クラステンプレートのインスタンス化の結果はクラスです!