関数テンプレートの詳細

5617 ワード

テンプレートはc++汎用プログラミングの基礎であり、汎用プログラミングは任意の特定のタイプとは独立した方法でコードを記述する.テンプレートは、汎用クラスまたは関数を作成する青写真または式です.例えば反復器やアルゴリズムは、汎用プログラミングの例であり、テンプレートの概念を使用しています.C++では,テンプレートは関数テンプレートとクラステンプレートの2種類に分けられる.関数テンプレートは関数を生成するために使用され、クラステンプレートはクラスを生成するために使用されます.
コンテナを例にとると、各コンテナにはvectorやvectorなどの単一の定義があります.テンプレートを使用して関数とクラスを定義できます.次に、関数テンプレートを見てみましょう.
テンプレートの使用方法:
template 
//        (    )
{
    //   
}

関数テンプレートの特性を以下の名詞で説明する.
1.関数テンプレート.
関数テンプレートとは、関数を生成するためのテンプレートです.
2.テンプレート関数.
テンプレート関数とは、テンプレートで定義され、複数のタイプをサポートする関数を指します.
3.テンプレートのインスタンス化.
テンプレートのインスタンス化とは、関数テンプレート(クラステンプレート)がテンプレート関数(テンプレートクラス)を生成するプロセスを指します.
4.テンプレートの実参推論.
関数テンプレートが呼び出されると、関数実パラメータタイプのチェックがテンプレート実パラメータのタイプと値を決定するプロセスをテンプレート実パラメータ推論と呼ぶ.注意事項:1.コンパイラに二義性を生じさせることはできない. 2.関数に実パラメータを渡す必要があります.
テンプレート関数に実パラメータを渡す過程で、sum(5,6)などの実パラメータタイプを指定できます.タイプsum(5,6)を指定しなくてもよい.呼び出しポイントにテンプレートタイプが指定されていない場合、コンパイラはパラメータタイプを自動的に推論します.この過程をテンプレートの実参推論と呼ぶ.
#include

template 
T sum(T a, T b)
{
	return a+b;
}

int main()
{
	std::cout<(10,20)<<:endl return=""/>

5.テンプレートの特例化(専用化)
テンプレートは汎用プログラミングを満たすことができるが,特定の場合,特定のタイプに対して大部分のタイプのように処理できない場合は,テンプレートを特例化してこの問題を処理する必要がある.特例化も1.完全特例化は全特化とも呼ばれ、特例化が特定のタイプに具体化されることを指す.2.部分特例化は偏特化とも呼ばれ、特例化が一部のタイプにのみ具体化されることを指す.
特定のタイプが通常のテンプレートバージョンと例外バージョンを同時に満たす場合、例外バージョンが優先的に呼び出されます.これは、例外バージョンの優先度が通常のテンプレートバージョンよりも高いことを示します.
特例化バージョンのテンプレート関数を記述する際には、特例化バージョンが通常のテンプレートのインスタンス化ロジックに合致することに注意してください.
template
bool Compare(const T a, const T b)
{
	std::cout << "bool Compare(T,T)  :" << typeid(T).name() << std::endl;
	return a > b;
}

template<>
bool Compare(char*const a, char*const b)
{
	std::cout << "bool Compare(char*,char*)  :" << typeid(a).name() << std::endl;
	return strcmp(a, b) > 0;
}
int main()
{
	Compare(10, 20);
	Compare(10, 20);
	Compare(10.1, 20.1);
	Compare("hello", "world");
	return 0;
}

6.テンプレートのタイプパラメータ.
テンプレートのタイプパラメータはtemplateで定義され、テンプレートタイプパラメータを定義する際にtypenameとclassは同じ役割を果たします.
テンプレートのタイプパラメータは、テンプレートを使用するときに、タイプをパラメータとしてテンプレートに渡すことを意味します.例えば、上記の例のT,Eはテンプレートのタイプパラメータである.
7.テンプレートの非タイプパラメータ.
関数テンプレートとクラステンプレートの場合、テンプレートパラメータはタイプに限定されません.テンプレートはタイプパラメータを定義するだけでなく、テンプレートで非タイプパラメータを定義することもできます.非タイプパラメータとは何ですか.その名の通り、タイプではなく固定タイプの定数を表すことです.固定タイプには限界があり、整形、ポインタ、参照のみが非タイプのパラメータとして使用され、そのパラメータにバインドされた実パラメータは定数式、すなわちコンパイル期間で結果を確認する必要があります.
非タイプパラメータの制限:
1).浮動小数点数はfloat,doubleを含む非タイプパラメータとして使用できません.具体的な原因は歴史的要因かもしれないし、将来C++が浮動小数点数をサポートするかもしれない.
2).クラスは非タイプパラメータとして使用できません.
3).文字列は非タイプパラメータとして使用できません
4).整形、整形に変換できるタイプは、int、char、long、unsigned、bool、shortなどのパラメータとして使用できますが、一般的にはパラメータとしてintに渡すことはできません.
5).オブジェクトまたは関数へのポインタと参照(左参照)は、パラメータとして使用できます.
非タイプの実パラメータの制限:
1).実パラメータはコンパイル時定数式でなければなりません.const以外のローカル変数、ローカルオブジェクトアドレス、動的オブジェクトは使用できません.
2).Const以外のグローバルポインタ、グローバルオブジェクト、グローバル変数(以下、特例がある場合があります)は定数式ではありません.
3).パラメータはすでに限定されているため、文字列、浮動小数点型は定数式でも非タイプの実パラメータとして使用できません.
備考:定数式は基本的に字面値およびconst修飾の変数です.
template
void Sort1(T arr[])
{
	//LEN = 10;
	T tmp = T();
	for (int i = 0; i < LEN - 1; i++)
	{
		for (int j = 0; j < LEN - i - 1; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}
template
void Show(T arr[], int len)
{
	for (int i = 0; i < len; i++)
	{
		std::cout << arr[i] << " ";
	}
	std::cout << std::endl;
}
int main()
{
	int arr[] = { 21, 32, 43, 234, 23, 42, 4212, 3 };
	int len = sizeof(arr) / sizeof(arr[0]);
	Show(arr, len);
	Sort(arr, len);
	Show(arr, len);

	return 0;
}

8.テンプレートのデフォルト値.
テンプレートのタイプパラメータリストは、実パラメータタイプを自動的に推論する機能だけでなく、デフォルト値を付与する操作もできます.ただし、関数テンプレートのデフォルト値とクラステンプレートの大きいデフォルト値にはいくつかの違いがあることに注意してください.
関数テンプレートのデフォルト値には、次のような特徴があります.
1).パラメータ推論を優先的に使用します.つまり、関数に実パラメトリック推論がある場合、コンパイラはテンプレートのデフォルト値を使用せず、逆に使用します.
2).関数テンプレートのデフォルト値の割り当ては、関数のデフォルト値の割り当てが右から左に順番に与えられるルールに従いません.ただし、クラステンプレートのデフォルト値は、右から左に順に与えられるルールに従います.
 
template
C Add(A a, B b)
{
	//C c = C();
	std::cout << "A : " << typeid(A).name() << std::endl;
	std::cout << "B : " << typeid(B).name() << std::endl;
	std::cout << "C : " << typeid(C).name() << std::endl;
	return a + b;
}

int main()
{
	auto rt = Add(10.1, 20);
	std::cout << "rt : " << typeid(rt).name() << std::endl;
	return 0;
}

9.テンプレートは、不明なタイプの戻り値を受信します.
テンプレートは不明確なタイプの戻り値を受け取ることができ、テンプレート関数の戻り値のタイプが不明確な場合はautoキーワードで代用することができます.autoは適応型の機能を有する.
10.テンプレートのリロード.
テンプレートは、通常の関数バージョン、テンプレートバージョン、テンプレートの特例化バージョンなど、リロードできます.この3つのバージョン間でリロードでき、リロード中にテンプレートのマッチングが正確に一致します.
11.テンプレートの表示をインスタンス化します.
testでcppファイルに関数テンプレートを作成しmain.cppファイルで呼び出され、呼び出せないことが判明した場合、テンプレートを表示インスタンス化する必要があります.
テンプレートを明示的にインスタンス化する場合、コンパイラはテンプレートを使用する前に、明示的にインスタンス化して指定したタイプに基づいてテンプレートインスタンスを生成します.フォーマットは、template int Sum(int,int);明示的なインスタンス化は宣言するだけで、再定義する必要はありません.コンパイラは、テンプレートに基づいてインスタンス宣言とインスタンス定義を実装します.
//test.cpp
template
T Sum(T a, T b)
{
	return a + b;
}
template int Sum(int, int);