C++: C++ テンプレート

最終更新:2026-08-31

これまで、特定の型の関数やクラスを書きました。

でも「intdoublestring で使える 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 型パラメータ>
戻り値型 関数名(パラメータ) {
    // ...
}
💡 ヒント: typenameclass と書くこともできます(同じ意味)、でも 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 に書くと、リンカエラー

原因: テンプレートはコンパイル時に具体的な型のコードを生成する「青写真」。

(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::vectorstd::array
  • アルゴリズム(std::sortstd::find
  • ユーティリティ関数(std::maxstd::minstd::swap

📖 まとめ


📝 練習問題

  1. 初級(難易度 ⭐): 関数テンプレート T min(T a, T b) を書いてください。小さい方の値を返す。

  2. 中級(難易度 ⭐⭐): クラステンプレート Box<T> を書いてください。T 型のメンバーを持ち、void set(T val)T get() メンバー関数を持つ。

  3. 上級(難易度 ⭐⭐⭐): 上の Array クラステンプレートを拡張:

    • void push_back(const T& val)(動的拡張)
    • void pop_back()
    • テンプレートで実装、異なる型でテスト


6. 🚀 次のステップ

テンプレートを理解したら、次は STLコンテナ(レッスン34) —— C++標準ライブラリのコンテナを使い、効率的なデータ管理を実現しよう!

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%