21:テンプレート入門

はじめに

C++のテンプレートとは、「型に依存しない」プログラムを作るための仕組みです。同じ処理を int 型、double 型、string 型などで繰り返し書く必要がなくなります。

1. 関数テンプレート

まずは、型ごとに異なる関数を作る代わりに、テンプレートを使う例を見てみましょう。

// 21_template_basic.cpp
#include <iostream>
#include <string>
using namespace std;

// 型に依存しないテンプレート関数
template <typename T>
void showValue(T value) {
    cout << "値: " << value << endl;
}

int main() {
    showValue(10);           // int型
    showValue(3.14);         // double型
    showValue('A');          // char型
    showValue(string("Hi")); // string型

    return 0;
}

template <typename T> では、T は「型の変数」であり、呼び出すときの実際の型に応じて自動的に置き換わります。

出力結果(例)

値: 10
値: 3.14
値: A
値: Hi

2. クラステンプレート

関数だけでなく、クラスにもテンプレートを使うことができます。「型を入れ替えられるクラス」を作ることで、汎用的なデータ構造を実現できます。

// 21_template_class.cpp
#include <iostream>
#include <string>
using namespace std;

template <typename T>
class Box {
private:
    T value;  // 保持する値
public:
    // コンストラクタ:初期値を受け取る
    Box(T initialValue) : value(initialValue) {}
    void show() {
        cout << "Boxの中身: " << value << endl;
    }
};

int main() {
    Box<int> intBox(123);          // int型のBox
    Box<double> dblBox(4.56);      // double型のBox
    Box<char> charBox('X');        // char型のBox
    Box<string> strBox("Hello");  // string型のBox

    intBox.show();
    dblBox.show();
    charBox.show();
    strBox.show();

    return 0;
}

出力結果(例)

Boxの中身: 123
Boxの中身: 4.56
Boxの中身: X
Boxの中身: Hello

3. テンプレートを使うメリット

メリット内容
再利用性型ごとに同じ処理を繰り返し書かなくてよい
保守性コードを1か所修正すれば全型に反映される
可読性「何をしているクラス・関数か」が明確になる

4. 注意点

ゲーム開発での例

テンプレートは、ゲーム開発でも便利です。例えば「スコア」「HP」「MP」など、さまざまな型の値を管理する共通クラスを作れます。

// 21_game_status_template.cpp
#include <iostream>
using namespace std;

template <typename T>
class Status {
private:
    T value;
public:
    Status(T v) : value(v) {}
    void set(T v) { value = v; }
    T get() { return value; }
};

int main() {
    Status<int> hp(100);     // HP(整数)
    Status<double> mp(35.5); // MP(小数)

    cout << "HP: " << hp.get() << endl;
    cout << "MP: " << mp.get() << endl;

    return 0;
}

実行結果(例)

HP: 100
MP: 35.5

理解度チェック(演習)

次のコードの出力を考えてみましょう(21_check_template.cpp)。

#include <iostream>
using namespace std;

template <typename T>
T multiply(T a, T b) {
    return a * b;
}

int main() {
    cout << multiply<int>(2, 3) << endl;
    cout << multiply<double>(1.5, 2.0) << endl;
    return 0;
}
正解を表示
6
3

演習問題(21_template_practice.cpp)

  1. テンプレート関数 maxValue(T a, T b) を作成し、大きい方の値を返すようにせよ。
  2. intdouble で試し、正しい値が返ることを確認せよ。
解答例
// 21_template_practice.cpp
#include <iostream>
using namespace std;

template <typename T>
T maxValue(T a, T b) {
    return (a > b) ? a : b;
}

int main() {
    cout << maxValue<int>(10, 20) << endl;      // 20
    cout << maxValue<double>(2.5, 1.8) << endl; // 2.5
    return 0;
}

コーディング演習

演習1:基本コードを動かす

21_01_template.cpp を作成し、関数テンプレート showValue のコードを入力して実行しましょう。int・double・char・string の4種類の型で動作を確認してください。

演習2:コードを改造する

21_01_Template21_template_basic.cpp をコピーして 21_02_TemplateMod に貼り付け、次の変更を加えてみましょう:

まとめ

理解度チェック

問題21-1

次のテンプレート関数 multiply<int>(3, 4) を呼び出したとき、戻り値はどれか。

template <typename T>
T multiply(T a, T b) { return a * b; }
解説を表示 正解:ウ
Tint になるので 3 * 4 = 12 が返る。テンプレートはコンパイル時に型が確定し、int multiply(int a, int b) として展開される。

問題21-2

クラステンプレートを使って Box<double> b(3.14); と宣言したとき、T の型はどれか。

解説を表示 正解:イ
Box<double> と指定しているので T = double。テンプレートの型引数は <> の中に明示する。

問題21-3

次のコードの出力として正しいものはどれか。

template <typename T>
T maxVal(T a, T b) { return (a > b) ? a : b; }
int main() {
    cout << maxVal<int>(5, 3) << endl;
    cout << maxVal<double>(2.1, 4.9) << endl;
}
解説を表示 正解:ア
maxVal<int>(5, 3) は 5 を返す(5 > 3)。maxVal<double>(2.1, 4.9) は 4.9 を返す(4.9 > 2.1)。テンプレートは型に応じて正しく動作する。

問題21-4

テンプレートを使う目的として最も不適切なものはどれか。

解説を表示 正解:エ
テンプレートの型はコンパイル時に確定する(静的)。実行時に型を動的に変換する機能ではない。動的な型変換は仮想関数やポリモーフィズムの役割。