C++/テンプレート

出典: フリー教科書『ウィキブックス(Wikibooks)』
< 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型などに対して作成したい場合があります。この時には、型をパラメータとして与えることが出来ると便利です。テンプレートは、

template <typename T, ...> Tを用いた関数定義

という表記を用いることで;構文:

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

定義することが出来ます。ここで、Tは区別するために用いられる型名で、どのような文字列を用いてもかまいません。テンプレートを用いて定義された関数を用いるには、

関数名 <型名, ...> (引数)

として呼び出すことが出来ます。型名は曖昧でなければ省略することが出来ます。

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

これは、2つの数を与えて大きい方を取り出すための関数です。実際にこの関数を用いる時には、

max (1,2);
max (1.0, 3.0);
max<double>(1,3.0); // 明示的に型を指定

などとします。

C言語では、これらの機能を実現する際にマクロを用いて、

#define max(a, b) ((a > b)?(a):(b))
とすることが通例でした。しかし、ここではaとbが異なる型を用いているときの扱いがテンプレートを用いている場合と比べてわかりづらくなります。
また、max(i++,j--); の様に副作用がある式を引数に与えると、意図せず二度評価してしまいます。
このため、C++では出来る限りテンプレートを使う方がよいでしょう。

クラステンプレート[編集]

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

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

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

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

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

関連項目[編集]