C++テンプレートベースの関数テンプレートとクラステンプレートの実例


プログラミング
もし関数を作成してもらうなら、二つの数の交換に使います。C言語では、私たちは次のような方法を使います。

//       
void Swapi(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
//           
void Swapd(double* p1, double* p2)
{
	double tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
C言語は関数の再負荷をサポートしていないため、異なるタイプの変数を交換するための関数名は同じではなく、参照形式はアドレス伝達でなければならず、値伝達ではない。
 C++の関数を勉強した後、私達はまた次の方法で二つの数の交換を実現します。

//       
void Swap(int& x, int& y)
{
	int tmp = x;
	x = y;
	y = tmp;
}
//           
void Swap(double& x, double& y)
{
	double tmp = x;
	x = y;
	y = tmp;
}
異なる型の変数を交換するための関数は同じ関数名を持つことができ、参照参照参照参照参照参照参照参照を使用して、コードが難しく見えないようにします。
しかし、このコードにはまだ足りないところがあります。
 1、重負荷の複数の関数はただタイプが異なるだけで、コードの多重化率は比較的に低いので、新しいタイプが現れたら交換が必要で、対応する重負荷関数を追加する必要があります。
 2、コードの維持性が低いです。この中の一つの重負荷関数にエラーが発生したということは、すべての重負荷関数にエラーが発生したということです。
コンパイラにモデルを教えてもらえませんか?コンパイラはタイプによってコードを生成します。
 は月餅の型を作るように、私達は異なった色の材料を入れて、形が同じですが、色が違った月餅を得ることができます。
C++においても、この金型に異なる色の材料(タイプ)を充填することにより、形が同じですが、色の異なる月餅(具体的なタイプのコードを生成する)を得ることができます。コードの冗長性を大幅に減らすことができます。巧いのは前人がとっくに木を植えています。ここで涼むだけです。
汎型プログラミング:タイプに関係のない汎用コードを作成することは、コード多重化の手段である。テンプレートは、一般的なプログラミングの基本です。

関数テンプレート
関数テンプレートの概念
 関数テンプレートはタイプに関係なく、使用時にパラメータ化され、パラメータタイプによって関数の特定のタイプのバージョンが生成される関数家族を表しています。
関数テンプレートの書式
template
タイプ関数名(パラメータリスト)を返します。
{
  //関数体
)
たとえば:

template<typename T>
void Swap(T& x, T& y)
{
	T tmp = x;
	x = y;
	y = tmp;
}
注意:typenameはテンプレートパラメータを定義するキーワードで、クラスで代用することもできますが、structでは代用できません。
関数テンプレートの原理
関数テンプレートの下の原理は何ですか?ご存知のように、ワットは蒸気機関を改良し、人類は工業革命を始め、生産力を解放しました。機械の生産は多くの手工芸品を淘汰した。その本質は重複した仕事を機械に任せて完成させることです。ある人は論調を与えました。怠け者は世界を創造します。
世界は怠け者が作ったものです。
怠けているのは怠け者ではありません。怠けたいなら、怠け者の方法を考え出してください。怠惰に風格を出して、怠惰に境界を出ます。
関数テンプレートは青写真です。それ自体は関数ではありません。コンパイラが特定のタイプ関数を生成する金型です。ですから、テンプレートとは本来私たちがすべきことをリピートしたものをコンパイラに渡しています。

コンパイラのコンパイラ段階では、関数テンプレートの使用に対して、コンパイラは、呼び出しのために、入力されたパラメータタイプに応じて、対応するタイプの関数を生成する必要があります。例えば、intタイプで関数テンプレートを使用する場合、コンパイラは、実際のパラメータタイプの推論により、Tタイプをintタイプとして決定し、専用のintタイプのコードを生成し、doubleタイプに対しても同様である。
関数テンプレートの実装
 を異なる種類のパラメータでテンプレートを使用する場合、テンプレートの実例化といいます。テンプレートの実例化は、暗黙的な実例化と表示の実例化に分けられます。
一、暗黙的な実例化:コンパイラを実際の参試テンプレートのパラメータの実際のタイプに基づいて推演させる

#include <iostream>
using namespace std;
template<typename T>
T Add(const T& x, const T& y)
{
	return x + y;
}
int main()
{
	int a = 10, b = 20;
	int c = Add(a, b); //       a b        int  
	return 0;
}
特に注意してください。テンプレートを使うと、コンパイラは一般的にタイプ変換操作をしません。したがって、以下のコードはコンパイルできません。

	int a = 10;
	double b = 1.1;
	int c = Add(a, b);
コンパイル中に、コンパイラが実際のテンプレートパラメータの種類に応じて、実際の参加aによるT推論をintとして、実際の参加bによるT推論をdoubleとしたが、テンプレートパラメータリストにはTしかないので、コンパイラはここでTをintとするべきかdoubleとするべきかを判断できない。
この時、私達は2つの処理方法があります。一つ目は私達が参参する時にbを強制的にintタイプに変換します。二つ目は以下に述べた表示の実用化を使います。
二、実例を表示します。関数名の後の<>でテンプレートパラメータの実際のタイプを指定します。

#include <iostream>
using namespace std;
template<typename T>
T Add(const T& x, const T& y)
{
	return x + y;
}
int main()
{
	int a = 10;
	double b = 1.1;
	int c = Add<int>(a, b); //            int
	return 0;
}
注意:表示の実装時に、入力されたパラメータタイプがテンプレートのパラメータタイプと一致しない場合、コンパイラは暗黙的なタイプの変換を試みます。もしうまく変換できない場合、コンパイラはエラーが発生します。
関数テンプレートのマッチング原則
一、テンプレート以外の関数は、同じ名前の関数テンプレートと同時に存在することができます。また、この関数テンプレートは、この非テンプレート関数として実装することもできます。

#include <iostream>
using namespace std;
//    int          
int Add(const int& x, const int& y)
{
	return x + y;
}
//           
template<typename T>
T Add(const T& x, const T& y)
{
	return x + y;
}
int main()
{
	int a = 10, b = 20;
	int c = Add(a, b); //       ,         
	int d = Add<int>(a, b); //         Add  
	return 0;
}
二、テンプレート関数ではなく、同じ名前の関数テンプレートに対して、他の条件が同じであれば、テンプレート関数以外のものを優先的に呼び出します。テンプレートがよりよくマッチする関数を生成できる場合は、テンプレートを選択します。

#include <iostream>
using namespace std;
//    int          
int Add(const int& x, const int& y)
{
	return x + y;
}
//           
template<typename T>
T Add(const T& x, const T& y)
{
	return x + y;
}
int main()
{
	int a = Add(10, 20); //          ,          
	int b = Add(2, 2.2); //               ,               Add  
	return 0;
}
三、テンプレート関数では自動タイプの変換はできませんが、普通の関数では自動タイプの変換ができます。

#include <iostream>
using namespace std;
template<typename T>
T Add(const T& x, const T& y)
{
	return x + y;
}
int main()
{
	int a = Add(2, 2.2); //             ,      
	return 0;
}
 テンプレート関数は自動タイプの変換を許さないので、2を自動的に2.0に変換したり、2.2を自動的に2に変換したりしません。
クラステンプレート
クラステンプレートの定義書式
template<クラスT 1、クラスT 2、…、クラスTn>
クラステンプレート名
{
  //部内メンバー声明

たとえば:

template<class T>
class Score
{
public:
	void Print()
	{
		cout << "  :" << _Math << endl;
		cout << "  :" << _Chinese << endl;
		cout << "  :" << _English << endl;
	}
private:
	T _Math;
	T _Chinese;
	T _English;
};
注意:クラステンプレートのメンバー関数をクラス外で定義する場合は、テンプレートパラメータリストを追加する必要があります。

template<class T>
class Score
{
public:
	void Print();
private:
	T _Math;
	T _Chinese;
	T _English;
};
//              ,         
template<class T>
void Score<T>::Print()
{
	cout << "  :" << _Math << endl;
	cout << "  :" << _Chinese << endl;
	cout << "  :" << _English << endl;
}
このほか、クラステンプレートは分離コンパイルをサポートしていません。つまり、xxx.hファイルで定義されていますが、xx.cppファイルで定義されています。
クラステンプレートの実装
 類テンプレートの実装は、関数テンプレートの実装とは異なり、クラステンプレートの実装は、クラステンプレート名の後に<>をつけ、実用化されたタイプを<>に置く必要があります。

    //Score      ,Score<int> Score<double>      
	Score<int> s1;
	Score<double> s2;
注意:クラステンプレートの名前は本当のクラスではなく、実際のクラスの結果です。
締め括りをつける
ここでC++テンプレートの基礎となる関数テンプレートとテンプレートについての記事を紹介します。これに関連して、C++関数テンプレートとテンプレートの内容は以前の文章を検索してください。または下記の関連記事を引き続きご覧ください。これからもよろしくお願いします。