C++/テンプレート
C++のテンプレートは、汎用的なプログラムを記述するための非常に強力な機能です。テンプレートを使用することで、型に依存しないコードを一度だけ記述し、様々な型に対して再利用することができます。テンプレートは主に関数テンプレートとクラステンプレートに分けられます。
関数テンプレート
編集関数テンプレートは、異なるデータ型に対して同じ処理を行う関数を定義するのに使われます。例えば、2つの値を比較するmax
関数を考えてみましょう。
template<typename T> T max(T a, T b) { return (a > b) ? a : b; } auto main() -> int { int a{5}, b{10}; double x{5.5}, y{10.1}; std::cout << max(a, b) << std::endl; // int型のmaxを呼び出す std::cout << max(x, y) << std::endl; // double型のmaxを呼び出す return 0; }
この例では、max
関数はテンプレート引数T
によって任意の型を受け取ることができます。コンパイラは、max
関数が呼び出された際に適切な型に対して具体化された関数を生成します。
クラステンプレート
編集クラステンプレートは、異なるデータ型に対して同じクラス定義を使用するためのテンプレートを作成します。例えば、単純なスタッククラスをテンプレート化する場合を考えてみましょう。
template<typename T> class Stack { private: std::vector<T> elems; public: void push(const T& elem) { elems.push_back(elem); } void pop() { if (elems.empty()) { throw std::out_of_range("Stack<>::pop(): empty stack"); } elems.pop_back(); } auto top() const -> T { if (elems.empty()) { throw std::out_of_range("Stack<>::top(): empty stack"); } return elems.back(); } auto empty() const -> bool { return elems.empty(); } }; auto main() -> int { Stack<int> intStack; Stack<std::string> stringStack; intStack.push(1); intStack.push(2); std::cout << intStack.top() << std::endl; // 出力: 2 intStack.pop(); std::cout << intStack.top() << std::endl; // 出力: 1 stringStack.push("hello"); stringStack.push("world"); std::cout << stringStack.top() << std::endl; // 出力: world stringStack.pop(); std::cout << stringStack.top() << std::endl; // 出力: hello return 0; }
この例では、Stack
クラスがテンプレート化されており、異なる型(int
やstd::string
など)に対して使用することができます。
テンプレートの特殊化
編集テンプレートの特殊化を使うことで、特定の型に対して異なる実装を提供することができます。これは主に、特定の型に対する最適化や特別な処理が必要な場合に使用されます。
template<typename T> class Printer { public: void print(const T& value) { std::cout << "Generic printer: " << value << std::endl; } }; // char型に対する特殊化 template<> class Printer<char> { public: void print(const char& value) { std::cout << "Char printer: " << value << std::endl; } }; auto main() -> int { Printer<int> intPrinter; Printer<char> charPrinter; intPrinter.print(123); // 出力: Generic printer: 123 charPrinter.print('A'); // 出力: Char printer: A return 0; }
この例では、Printer
クラステンプレートのchar
型に対する特殊化を行い、char
型の値に対して特別な出力を行うようにしています。
テンプレートのパラメータパック
編集C++11以降では、テンプレートパラメータパックを使用することで、可変長引数を取るテンプレートを定義することができます。これにより、任意の数のテンプレート引数を扱うことができます。
template<typename... Args> void printAll(const Args&... args) { (std::cout << ... << args) << std::endl; // C++17以降のFold Expression } auto main() -> int { printAll(1, 2.5, "hello", 'c'); // 出力: 12.5helloc return 0; }
この例では、printAll
関数が任意の数の引数を受け取り、それらをすべて標準出力に出力します。C++17のFold Expressionを使用して、可変長引数を一括処理しています。
まとめ
編集C++のテンプレートは、コードの再利用性を高め、異なるデータ型に対して汎用的なアルゴリズムやデータ構造を提供するための強力な機能です。関数テンプレートとクラステンプレートの基本を理解し、さらに特殊化やテンプレートパラメータパックなどの高度な機能を活用することで、柔軟で効率的なプログラムを作成することができます。