C++: C++ テンプレート
最終更新:2026-08-31
これまで、特定の型の関数やクラスを書きました。
でも「
int、double、stringで使えるmax関数」を書くには?テンプレートで解決 —— 関数とクラスを型に依存しない。
1. テンプレートとは?
(1) 1.1 テンプレートの概念
| 概念 | プログラムでの意味 |
|---|---|
| 汎用的な型(型をパラメータ化) | テンプレート |
| 型を埋めて具体的な関数・クラス(テンプレートのインスタンス化) | テンプレートのインスタンス化 |
テンプレートの目的: コンパイラが呼び出し元の型に応じて、具体的な関数・クラスを生成。
(2) 1.2 なぜテンプレートが必要?
テンプレートを使わない場合(関数オーバーロード):
TEXT
📖 参照専用
#include <iostream>
// int版のmax
int max(int a, int b) {
return a > b ? a : b;
}
// double版のmax
double max(double a, double b) {
return a > b ? a : b;
}
// ... N個の型に対してN個の関数を書く!
テンプレートを使う場合(1つのコード):
CPP
#include <iostream>
// テンプレート
template <typename T>
T max(T a, T b) {
return a > b ? a : b;
}
int main() {
std::cout << max(3, 5) << std::endl; // int版
std::cout << max(3.14, 2.72) << std::endl; // double版
return 0;
}
2. 関数テンプレート
(1) 2.1 基本的な構文
TEXT
📖 参照専用
template <typename 型パラメータ>
戻り値型 関数名(パラメータ) {
// ...
}
💡 ヒント:
typename は class と書くこともできます(同じ意味)、でも typename を推奨(より明確)。
▶ サンプル 1:関数テンプレート(難易度 ⭐)
CPP
#include <iostream>
// テンプレート
template <typename T>
T max(T a, T b) {
return a > b ? a : b;
}
int main() {
std::cout << "max(3, 5) = " << max(3, 5) << std::endl;
std::cout << "max(3.14, 2.72) = " << max(3.14, 2.72) << std::endl;
// 明示的な型指定
std::cout << "max<int>(3, 5) = " << max<int>(3, 5) << std::endl;
return 0;
}
出力:
TEXT
📖 参照専用
max(3, 5) = 5
max(3.14, 2.72) = 3.14
max<int>(3, 5) = 5
3. クラステンプレート
(1) 3.1 基本的な構文
TEXT
📖 参照専用
template <typename 型パラメータ>
class クラス名 {
// ...
};
▶ サンプル 2:クラステンプレート Pair(難易度 ⭐⭐)
CPP
#include <iostream>
#include <string>
// テンプレート
template <typename T1, typename T2>
class Pair {
private:
T1 first;
T2 second;
public:
Pair(const T1& a, const T2& b) : first(a), second(b) {}
void print() {
std::cout << "(" << first << ", " << second << ")" << std::endl;
}
};
int main() {
Pair<int, double> p1(3, 3.14);
Pair<std::string, int> p2("Alice", 20);
p1.print(); // (3, 3.14)
p2.print(); // (Alice, 20)
return 0;
}
💡 ヒント: クラステンプレートを使うには型を明示(コンストラクタで型推論はC++17以降)。
4. テンプレートの宣言と定義
(1) 4.1 問題:テンプレートを分割すると?
テンプレートの宣言を .h、定義を .cpp に書くと、リンカエラー!
原因: テンプレートはコンパイル時に具体的な型のコードを生成する「青写真」。
- 宣言を
.h、定義を.cppに書くと、コンパイラは.cppをコンパイルする際に型が不明。 - 呼び出し元でテンプレートを使うまで、コンパイラはコードを生成できない。
(2) 4.2 解決策:宣言と定義を同じファイルに
推奨: テンプレートの宣言と定義を .h ファイルに書く。
TEXT
📖 参照専用
// pair.h(ヘッダファイル)
#ifndef PAIR_H
#define PAIR_H
template <typename T1, typename T2>
class Pair {
private:
T1 first;
T2 second;
public:
Pair(const T1& a, const T2& b);
void print();
};
// 定義も同じファイルに!
template <typename T1, typename T2>
Pair<T1, T2>::Pair(const T1& a, const T2& b) : first(a), second(b) {}
template <typename T1, typename T2>
void Pair<T1, T2>::print() {
std::cout << "(" << first << ", " << second << ")" << std::endl;
}
#endif
💡 違い: テンプレートと通常の関数・クラスの違い —— テンプレートは宣言と定義を同じファイルに。
5. 実践例:配列テンプレート
▶ サンプル 3:Array クラステンプレートの実装(難易度 ⭐⭐⭐)
CPP
#include <iostream>
#include <cassert>
template <typename T>
class Array {
private:
T* data;
int size;
public:
Array(int sz) : size(sz) {
data = new T[size];
}
~Array() {
delete[] data;
}
// コピーコンストラクタ(ディープコピー)
Array(const Array& other) : size(other.size) {
data = new T[size];
for (int i = 0; i < size; i++) {
data[i] = other.data[i];
}
}
// 添字演算子
T& operator[](int index) {
assert(index >= 0 && index < size);
return data[index];
}
int getSize() const {
return size;
}
};
int main() {
Array<int> arr(5);
for (int i = 0; i < arr.getSize(); i++) {
arr[i] = (i + 1) * 10;
}
for (int i = 0; i < arr.getSize(); i++) {
std::cout << arr[i] << " ";
}
std::cout << std::endl;
return 0;
}
❓ よくある質問
Q: テンプレートと関数オーバーロードの違いは? A:
- 関数オーバーロード:複数の関数を定義、型ごとに異なる実装(コンパイル時に呼び出す関数を決定)
- 関数テンプレート:「青写真」を1つ書く、コンパイラが呼び出し元の型に応じて具体的な関数を生成
使い分け:型によって大きく実装が異なる場合、オーバーロードを使う;実装が同じ場合、テンプレートを使う。
Q: テンプレートに型制約はある? A: あります!テンプレートの型パラメータは、その型で使う操作をサポートする必要がある。
CPP
template<typename T>
T add(T a, T b) {
return a + b; // Tはoperator+をサポートする必要がある
}
// Tが自作クラスの場合、そのクラスでoperator+をオーバーロードしないとコンパイルエラー。
Q: いつテンプレートを使う? A: 型に依存しない関数・クラスを実装する場合。
例:
- コンテナクラス(
std::vector、std::array)- アルゴリズム(
std::sort、std::find)- ユーティリティ関数(
std::max、std::min、std::swap)
📖 まとめ
- テンプレートは関数とクラスを型に依存しない
- 関数テンプレート:
template<typename T>T foo(T x) { ... } - クラステンプレート:
template<typename T>class Foo { ... }; - テンプレートの宣言と定義は同じファイルに(
.hファイル) - テンプレートの関数・クラスは、コンパイル時にコードを生成する「青写真」
📝 練習問題
-
初級(難易度 ⭐): 関数テンプレート
T min(T a, T b)を書いてください。小さい方の値を返す。 -
中級(難易度 ⭐⭐): クラステンプレート
Box<T>を書いてください。T型のメンバーを持ち、void set(T val)とT get()メンバー関数を持つ。 -
上級(難易度 ⭐⭐⭐): 上の
Arrayクラステンプレートを拡張:void push_back(const T& val)(動的拡張)void pop_back()- テンプレートで実装、異なる型でテスト
6. 🚀 次のステップ
テンプレートを理解したら、次は STLコンテナ(レッスン34) —— C++標準ライブラリのコンテナを使い、効率的なデータ管理を実現しよう!