C++/テンプレート

< C++

テンプレート編集

C++のテンプレートは、パラメーター化された型です。

C++11には、以下の4種類のテンプレートがあります。

関数テンプレート編集

関数テンプレートを使うと、関数を使う際、引数の型についての場合わけの手間を減らせる可能性があります。たとえば数値型と文字列型といった異なる型ごとに別々に関数を作らなくても済むようになります。

構文
template <typename 型引数名> 戻値型 関数名(引数リスト) { /* 関数本体 */}
コード例
#include <iostream>
#include <string> // string クラスを使うので忘れないように
using std::cout, std::showpoint, std::endl, std::string;

// 関数テンプレートの定義
template <typename T> T plus(T a, T b) {
  return a + b;
};

int main() {
  int i{3}, j{4};
  string s{"abc"}, t{"123"};
  
  cout << showpoint; // 浮動小数点数をわかり易く表示

  cout << plus(i, j) << endl;
  cout << plus<double>(i, j) << endl;
  cout << plus(s, t) << endl;
}
出力結果
7
7.00000 
abc123
typename の部分は、C++のキーワードです。
class でも同じ意味です。
plusは関数名です。自由に変えて構いません。
「T」の部分は、型引数名です。関数の定義文の引数と戻値の型が、この「T」に置換わっている事に注目してください。
テンプレート用の関数の定義文は、通常の関数とちがい、型引数で引数、関数の中で定義される変数、戻値の型を決めることが出来ます。
利点
もし関数テンプレートを使わずに通常の関数だけで同じ結果の処理をやろうとすると、関数を2個、別々に作る必要があります。
これに対し、関数テンプレートを使えば、関数の定義は1つだけで済み、アルゴリズムの共有が出来ます。
備考

テンプレートの宣言の際、

template <typename T> 
T plus(T a, T b) {
  return a + b;
};
のように template <typename T> で改行して紹介する書籍などもよくあります。
もともと1文で定義する構文ですので、間違えてセミコロンなどを改行位置で加えないように気をつけましょう。

詳細編集

関数テンプレートは、型をパラメータとして受取る機能です。 例えば最大値・最小値のように、同じアルゴリズムをint, doubleやクラスに対し適用したい場合があります。 この時、型の組合わせだけ同じアルゴリズムの関数を定義するのは煩雑で修正漏れが出がちです。 そこで、型をパラメータとして受取る機能(ジェネリックプログラミング)が考案され、C++ではその目的にテンプレートが用意されています。

テンプレート関数定義の構文
template <typename T> T 関数名(T 引数, T 引数 ) {
  /* 関数本体 */
}
Tはパタメータ化された型(型引数)で、引数や戻値やローカル変数の型に使うことができます。
型引数は、識別子として有効ならば名前は任意です。
テンプレート関数呼出しの構文
関数名<>(引数リスト);
型は曖昧でなければ省略することが出来ます。
#include <iostream>
using std::cout, std::endl;

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

int main() {
  cout << "max(1, 2) => " << max(1, 2) << endl;
  cout << "max(3.1, 2.5) => " << max(3.1, 2.5) << endl;
  cout << "max<double>(5.2, 3) => " << max<double>(5.2, 3) << endl; // note: candidate template ignored: deduced conflicting types for parameter 'T' ('int' vs. 'double')
}
実行結果
max(1, 2) => 2
max(3.1, 2.5) => 3.1 
max<double>(5.2, 3) => 5.2
maxは、2つの数を与えて大きい方を取り出すための関数です。
引数同士の型が一致しているときに限りテンプレート関数の<型引数>は省略できます。

C言語では、同様の機能をマクロを使って

#define max(a, b) ((a > b)?(a):(b))
のように実装してきました。
マクロの場合、max(i++,j--); の様に副作用がある式を引数に与えると、意図せず二度評価してしまいます。
このため、C++では出来る限りテンプレートを使う方がよいでしょう。

クラステンプレート編集

構文
template <typename 型引数名> class クラス名 {
  /* クラス本体 */
};

メンバーテンプレート編集

構文
class クラス名 {
  template <typename 型引数名>
  /* クラス本体 */
  // メンバー(プロパティとメソッド)で型引数名を型に使える
};

エイリアステンプレート編集

構文
template <typename T> 
using ユーザー定義型 = Tを使った型定義 ;


関連項目編集