C++のテンプレート機能を使ってみた

C++にはテンプレートという便利な機能があります。存在自体は書籍などで知っていたのですが、今回実際に使ってみました。
独立したコンセプトは、独立に表現すべきであり、必要なとき以外は結合すべきではない。この原則に従わないと、無関係なコンセプトを結び付けたり、不必要な依存関係を持ち込んだりすることになる。いずれにしても、システムを構成する部品としては柔軟性の低いものしか手に入らない。
(プログラミング言語C++ 第3版 「第13章 テンプレート」より)

テンプレートは文字通り雛形です。クラスの雛形、関数の雛形などが作成できます。

例えば以下のような簡単なクラスXの雛形を作ってみました。 まず雛形の定義を行います。<と>の中に記述しているclass Cは何らかの型を表します。これはtypename Cとも書けます。CでなくともAでもBでもZでも構いません。雛形クラス内で使用するためにとりあえずCという型にしておくという程度のものです。

#include <iostream>
using namespace std;

//テンプレートの宣言
template<class C> class X; //何らかの型を持つXというクラスの雛形を宣言

次にこの雛形クラスの定義を行います。定義自体は普通のクラスと変わりません。違いは特定の型ではなく何らかの型を使うという点のみです。 この何らかの型は実際にクラスを使用する際に実際の型名が渡され、「何らかの型」が「特定の型」に置き換えられてインスタンス化されます。

//テンプレートの定義
template<class C>
class X {
  C a;
public:
  void set(C b) {
    a = b;
  }
  C get() {
    return a;
  }
};

ではこの雛形クラスを実際に使ってみます。 クラスを指定する際に、以下のように<と>で囲んでこのクラス内で使用する実際の型を指定します。以下の場合char型を指定しています。

int main() {
  X<char> char_buf;
  char_buf.set('a');
  cout << char_buf.get() << endl;
  char_buf.set('b');
  cout << char_buf.get() << endl;

  return 0;
}

そのため以下のクラスをインスタンス化するのと同じことになります。

class X {
  char a;
public:
  void set(char b) {
    a = b;
  }
  char get() {
    return a;
  }
};

当然ですが、set()関数はchar型bを受け取り、char型インスタンス変数aに代入します。get()はchar型インスタンス変数aを返します。

出力は、

a
b

になります。

これだけだとそれがどうした?となるのですが、雛形である以上、「何らかの型」(C)に様々な型を指定することで、1つの雛形から複数の(違う型を持つ)クラスをいくつも生成できるのです。

例えばint型を持つXクラスのインスタンスを生成する場合は以下のようにします。<と>の中をcharからintに変えただけです。

  X<int> int_buf;
  int_buf.set(1);
  cout << int_buf.get() << endl;
  int_buf.set(2);
  cout << int_buf.get() << endl;

これは以下のクラスをインスタンス化するのと同じことになります。

class X {
  int a;
public:
  void set(int b) {
    a = b;
  }
  int get() {
    return a;
  }
};

出力は、

1
2

になります。

1つの定義で何度も美味しい、それがテンプレートになります。

公開日:2020年11月13日

記事 > C++言語 > C++のテンプレート機能を使ってみた

C++言語の記事一覧

他の記事も見る

このページのトップに戻る