テンプレート関数


汎用関数

ここでは、C++言語の高い柔軟性の実現の一つ
テンプレートについて、説明していきます
テンプレートの概念は、オブジェクト指向で名高い Java にすらない、すばらしい機能です

プログラムでは、内部処理は同じだがデータ型が異なる関数が頻繁に出てきます
とくにアルゴリズムにおける関数では、その様なケースが多いです

全てのデータ型の関数をオーバーロードでサポートするのも一つの方法ですが
この作業は面倒で、しかもソースの可読性も低下させてしまいます
そこで、この作業を全てコンパイラに任せてしまうのが汎用関数なのです

汎用関数は、各データ型を受け取ることができます
しかし、オーバーロードとは異なり内部処理は同じです
このような汎用関数をテンプレート関数とも呼び
次のように template キーワードを用いて宣言します

template <class type> function-declarator

function-declarator は、関数の宣言を行います
type は、関数が受け取る汎用データ型のです
もちろん、そんなものが実際に存在するわけではなく
コンパイル時に、それぞれの型に対応した関数が生成され
type は各データ型に置きかえられます
#include <iostream>
using namespace std;

template <class X> void println(X out) {
	cout << out << '\n';
}

int main() {
	println("Kitty on your lap");
	println(10);
	println(1.052);

	return 0;
}
このプログラムの println() は汎用関数です
受け取ったデータを出力するだけなので、内部処理はデータ型に関係ありません
main() 関数内部で、いろいろな型で println() を呼び出していますが
汎用関数 println() は、それぞれのデータ型に対応した println() をサポートしています

template <class X> void println(X out)テンプレート関数
|||インスタンシエート
void println(char *)void println(int)void println(double)生成された関数

上の図のように、使用されるデータ型に合わせてテンプレート関数はオーバーロードします
数学関数などで内部処理が同じだが、受け取るデータ型は整数や浮動小数点などが考えられる場合
テンプレートを用いた関数を使うと非常に簡単です

ソース上のテンプレート関数を、各データ型専用の関数に変換する工程をインスタンシエートと呼び
コンパイル後に各データ型用に作られた関数を生成された関数と呼びます

ここで使われる class キーワードは typename キーワードでもかまいません
比較的、一般的に使われるのは class キーワードです

template <typename type> function-declarator

また、テンプレートの定義は、関数の定義とは別のところで行うこともできます
ただし template 文と関数の間に別の文を挿入することはできません
#include <iostream>
using namespace std;

template <typename X>

X max(X var1 , X var2) {
	if (var1 > var2) return var1;
	else return var2;
}

int main() {
	cout << max(10 , 100);

	return 0;
}
template の引数の並びで、classの代わりに typename キーワードを使っています

また、複数の型を受け取る汎用関数の生成も可能です
tenplate の引数の並びで、カンマで型を区切り汎用データ型を複数定義します
#include <iostream>
using namespace std;

template <class X1 , class X2> void println(X1 var1 , X2 var2) {
	cout << var1 << " : " << var2 << '\n';
}

int main() {
	println(1000 , 56.025);
	println('A' , "Di Gi Gharat");
	println("Kitty on your lap" , "LOVE HINA");

	return 0;
}
こうすることで、異なるデータ型の組み合わせを自由に受け取れます
最後の println() のように、同じデータ型でも問題はありません


テンプレートのオーバーライド

テンプレートは型に応じて関数をオーバーロードすることはわかりました
あらゆるデータ型に対応できる、内部処理が同じ関数の生成を自動化できます

しかし、例えばほとんどのデータ型の処理は同じだが
整数型の時だけ、違う処理を行いたいような場合もあると思います
そのような場合は汎用関数をオーバーロードしてしまいます
つまり、明示的に目的の型でオーバーロードしてしまうことで、テンプレートを隠します
#include <iostream>
using namespace std;

template <class X> void println(X out) {
	cout << out << '\n';
}

void println(float out) {
	cout << 'F' << out << '\n';
}

int main() {
	println("Kitty on your lap");
	println(56.025f);
	println(100.01);

	return 0;
}
汎用関数 println() は、float 型を受け取った時のみ違う処理を行います
通常は汎用関数 println(X) を呼び出しますが
この関数は println(float) を明示的にオーバーロードすることで
float 型を受け取った時のみ、明示した関数を呼び出します

もっとも、データ型によって処理が異なる関数の生成は
テンプレートではなくて関数のオーバーロードが専門分野です
テンプレートの中のある特定のデータ型でのみ処理が異なるという場合に用います


template

template < [typelist] [ , [ arglist]] > declaration

パラメータ化した汎用関数、または汎用クラスを指定します

typelist - class または typename キーワードで、汎用データ型を定義します
arglist - 汎用データ型の引数リストです
declaration - 関数またはクラスを宣言します

typename

typename identifier

テンプレートの定義で用います
未知の識別子が型であることをコンパイラに通知します
このキーワードの代わりに class キーワードを用いることも可能です



前のページへ戻る次のページへ