【C++】テンプレート (template) 入門 | 汎用的な関数とクラスの作り方

目次

はじめに

C++のテンプレート (template) は、型をパラメータ化することで、汎用的なコードを書くための非常に強力な機能です。単に関数やクラスを汎用化するだけでなく、可変長の引数を扱ったり、特定の型に対して特別な処理を定義したりと、C++の表現力を飛躍的に向上させます。

この記事では、テンプレートの基本的な使い方から、可変長引数特殊化といった、より高度で実践的なトピックまでを網羅的に解説します。


1. 関数テンプレート

型に依存しない、汎用的な関数を定義します。コンパイラが引数の型から、実際に使用する型を自動的に推論します。

サンプルコード

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

// C++14以降のジェネリックラムダも関数テンプレートの一種
auto add = [](auto a, auto b) {
    return a + b;
};

解説: get_max関数は、intでもdoubleでもstringでも、>演算子が定義されている任意の型で動作します。


2. クラステンプレート

型に依存しない、汎用的なクラスを定義します。利用する際には、< >で具体的な型を明示的に指定する必要があります(C++17以降、一部推論可能)。

サンプルコード

template <typename T>
class Pair {
public:
    T first, second;
};

int main() {
    Pair<int> p_int; // Tをintとして実体化
    p_int.first = 10;
    
    // C++17以降のクラスのテンプレート引数推論 (CTAD)
    Pair p_double{3.14, 2.71}; // Tがdoubleであると自動推論
    return 0;
}

3. 可変長引数テンプレート (Variadic Templates)

C++11以降、任意の個数のテンプレート引数を受け取れるようになりました。printfのような、引数の数が可変の関数を型安全に実装できます。

サンプルコード

#include <iostream>

// ループの停止条件となるベース関数
void print_all() {
    std::cout << std::endl;
}

// 可変長引数テンプレートを使った再帰関数
template <typename T, typename... Args>
void print_all(const T& first, const Args&... rest) {
    std::cout << first << " ";
    print_all(rest...); // 残りの引数パックを展開して再帰呼び出し
}

int main() {
    print_all(1, "hello", 3.14); // 3つの異なる型の引数を渡す
    return 0;
}

4. エイリアステンプレート (Alias Templates)

C++11以降、using を使って、テンプレートに別名を付けることができます。複雑な型名を単純化するのに非常に便利です。

サンプルコード

#include <vector>
#include <string>

// vector<T>に、StringVector<T>という別名を付ける
template <typename T>
using StringMap = std::map<std::string, T>;

int main() {
    // std::map<std::string, int> と書くのと同じ
    StringMap<int> user_scores;
    user_scores["Taro"] = 100;
    return 0;
}

5. テンプレートの特殊化 (Template Specialization)

特定の型に対して、テンプレートの標準的な実装とは異なる、特別な実装を提供したい場合に使います。

サンプルコード

#include <iostream>
#include <vector>

// 汎用的なクラステンプレート
template <typename T>
class Container {
public:
    void print() { std::cout << "汎用テンプレート" << std::endl; }
};

// 1. Tがintの場合の「完全特殊化」
template <>
class Container<int> {
public:
    void print() { std::cout << "int型に特殊化されたテンプレート" << std::endl; }
};

// 2. Tがvector<U>の場合の「部分特殊化」
template <typename U>
class Container<std::vector<U>> {
public:
    void print() { std::cout << "vector型に部分特殊化されたテンプレート" << std::endl; }
};


int main() {
    Container<double> c_double;
    Container<int> c_int;
    Container<std::vector<char>> c_vector;

    c_double.print();
    c_int.print();
    c_vector.print();
    
    return 0;
}

解説: Containerは、int型で使われた場合と、vector型で使われた場合に、それぞれ専用の実装が呼び出されています。


まとめ

今回は、C++のテンプレートの基本的な機能から、可変長引数や特殊化といった高度なトピックまでを網羅的に解説しました。テンプレートはC++の静的なポリモーフィズムとジェネリックプログラミングを支える中核機能であり、STL(標準テンプレートライブラリ)の基盤となっています。これらの機能を理解することで、再利用性が高く、型安全で、効率的なコードを書くことが可能になります。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次