Template(雛形,テンプレート)について説明する.C++には生成的プログラミングという枠組みでのプログラミングを可能とする機能が存在し,それをTemplateと呼んでいる.この機能は2022年現在でも不完全に思えるため,教えるのに躊躇いがあるのだが,そこら中で使われるので知っていなければならない.
テンプレートは一つの定義で,複数の型に対応するコードを自動的に生成するものである.以下に示す例では,メンバ関数print を持つクラスであれば,どんなクラスであっても動く関数としてFが定義される.このコードをコンパイルした場合,クラスA用とクラスB用に引数の型が異なる2つの関数Fが生成される.
#include <iostream>
using namespace std;
template<class T>
void F(T t1){
t1.print();
}
int main(){
struct A{
void print(){
cout << "This is A\n";
}
};
struct B{
void print(){
cout << "This is B\n";
}
};
A a;
B b;
F(a);
F(b);
}
上記ファイルをt.cppとして保存しコンパイルと実行を行った結果を以下に示す
Pythonのような型が存在しない言語を使っている,あるいは普通の感覚で,このようなコードが実行できることは当然のように思えるかもしれないが,型が違えばほとんど同じコードの見た目であっても別の関数を定義しなければならないC++の規則から言ってこれは当然のことではない.逆に考え,型などというものをなくしたらどうだろうかとも思うが,型が決まっていることで,実行時に型を判定して計算機上でのデータの表現方法,つまり符号とその符号に適した処理内容を見つけ出すことをしなくて済むため,高速な実行が可能となる.このテンプレートは,型があることによるプログラミングの労力と,型があることによる高速な実行コード生成の両法を同時に可能としている.
テンプレートでは,特定の型にのみ別途処理を記述する方法があり,これを特殊化と呼ぶ.以下に例を示す.この例では,型 intにのみ特別に処理を記載している.
#include <iostream>
using namespace std;
template<class T>
void F(T t1){
t1.print();
}
template<>
void F(int t1){
cout << "this is int, special case: " << t1 << "\n";
}
int main(){
struct A{
void print(){
cout << "This is A\n";
}
};
struct B{
void print(){
cout << "This is B\n";
}
};
A a;
B b;
F(a);
F(b);
F(2);
}
実行結果を以下に示す.型intの引数が与えられた場合のみ,print()を呼び出すのではない特別な処理が行われていることを確認できる.
特殊化を引数の型による自動判定ではなく,明示的に行いたい場合は,得初夏において使いたい型をAとしたとき,関数の前に<A>と記載してから引数を与える.以下に例と実行結果を示す.
#include <iostream>
using namespace std;
template<class T>
void F(T t1){
t1.print();
}
template<>
void F(double t1){
cout << "this is double, special case: " << t1 << "\n";
}
int main(){
struct A{
void print(){
cout << "This is A\n";
}
};
struct B{
void print(){
cout << "This is B\n";
}
};
A a;
B b;
F(a);
F(b);
F(3.14159265358978);
F<double>(2);
}
double と intは同じ数値型であるが,テンプレートではそれぞれの型について特殊な定義を用意しなければならない.intの方はdoubleものもで代用できるため,27行目ではdoubleにより特殊化されたFを用いている.実行結果から意図したとおり動いていることが確認できる.