関数テンプレートは、異なる型に対して同じロジックを再利用可能な形で定義するためのC++の機能です。これにより、型ごとに個別の関数を記述する必要がなくなり、コードの保守性と拡張性が向上します。
1. 関数オーバーロードによる多型対応
従来のアプローチでは、各データ型ごとに同じ処理を行う関数を個別に定義(オーバーロード)する必要があります。
#include <iostream>
#include <string>
void exchange(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
void exchange(double& a, double& b) {
double temp = a;
a = b;
b = temp;
}
void exchange(std::string& a, std::string& b) {
std::string temp = a;
a = b;
b = temp;
}
int main() {
int i1 = 10, i2 = 20;
double d1 = 3.14, d2 = 4.56;
std::string s1 = "Morning", s2 = "Afternoon";
exchange(i1, i2);
exchange(d1, d2);
exchange(s1, s2);
std::cout << "i1=" << i1 << ", i2=" << i2 << '\n';
std::cout << "d1=" << d1 << ", d2=" << d2 << '\n';
std::cout << "s1=" << s1 << ", s2=" << s2 << '\n';
}
2. 関数テンプレートによる汎用実装
関数テンプレートを使うことで、単一の定義で任意の型に対応できます。
#include <iostream>
#include <string>
template<typename T>
void generic_swap(T& x, T& y) {
T tmp = x;
x = y;
y = tmp;
}
int main() {
int a = 10, b = 20;
double p = 3.1415, q = 2.5687;
std::string u = "morning", v = "afternoon";
generic_swap(a, b);
generic_swap(p, q);
generic_swap(u, v);
std::cout << "a=" << a << ", b=" << b << '\n';
std::cout << "p=" << p << ", q=" << q << '\n';
std::cout << "u=" << u << ", v=" << v << '\n';
}
この場合、コンパイラは呼び出し時に使用される引数の型から自動的に適切なインスタンスを生成します。明示的に型を指定することも可能です(例: generic_swap<double>(p, q))。
3. テンプレートの特殊化とオーバーロード
特定の型に対して異なる振る舞いを定義したい場合は、テンプレートの特殊化または通常の関数オーバーロードを利用できます。
#include <iostream>
#include <cstring>
template<typename T>
T select_min(const T& x, const T& y) {
return (x < y) ? x : y;
}
// Cスタイル文字列用のオーバーロード
const char* select_min(const char* s1, const char* s2) {
return (std::strcmp(s1, s2) < 0) ? s1 : s2;
}
int main() {
std::cout << select_min(10, 8) << '\n';
std::cout << select_min("morning", "afternoon") << '\n';
}
異なる型の引数(例: int と double)を混在させる場合、コンパイラは共通の型を推論できないため、明示的な型指定が必要です。たとえば、select_min<double>(10, 8.8) のように記述します。