読者です 読者をやめる 読者になる 読者になる

C++11/14 でテンプレートを使用する場面

C++03 ではせいぜいクラスや関数ぐらいでしかテンプレートを使う場面はなかったのですが C++11/14 でテンプレートを使う場面が増えたのでまとめてみました。

クラステンプレート(C++11)

クラスにテンプレート型を渡します。

template<typename T>
struct holder{
    T value;
};

holder<int>   n = { 10 };
holder<float> f = { 3.14f };

関数テンプレート(C++11)

関数にテンプレート型を渡します。

template<typename R, typename T>
R
twice(T t){
    return t + t;
}

int n1 = twice<int, int>(2);
int n2 = twice<int>(3.5);      // 引数型を省略することも可能

関数の場合は、引数からテンプレート型を推論する事ができるので、引数のテンプレート型を省略する事が出来ます。

エリアステンプレート(C++11)

C++11 から追加された template aliases という機能で使用します。 これは同じく C++11 で追加された using を使用した型エイリアス対してテンプレートを定義します。

// std::string をキーにした std::map 型を定義
template<typename T>
using my_map = std::map<std::string, T>;

my_map<int> table = {
    { "homu", 1 },
    { "mami", 2 },
    { "mado", 3 }
};

変数テンプレート(C++14)

これは C++14 から追加された機能ですが『すでに定義してる変数の型をテンプレートを使用してあとから定義する』ような機能になります。 例えば、『PI の値を任意の型で定義したい場合は次のように利用することが出来ます。

template<typename T>
T pi = static_cast<T>(3.141592);

int   i_pi = pi<int>;       // 3
float i_pi = pi<float>;     // 3.14159

これは pi<int> の場合は static_cast<int>(3.141592) が返ってきて、pi<float> の場合は static_cast<float>(3.141592) が返ってきます。 他のテンプレートとは違い pi<int>型ではなくて値が返ってくるのがすごく奇妙に感じますね。

可変長テンプレート引数(C++11)

これは、特定の場面で使用するわけではないですが(むしろテンプレートが使える場面ではどこでも使えますが)テンプレート型を可変長に受け取る事が出来ます。

template<typename... Args>
struct holder{
    std::tuple<Args...> data;
};

holder<int, float, bool> table = {{ 42, 3.14f, false }};

上記のコードは簡単な例ですが、今回上げた中では一番学習コストが高い機能だと思います。
他には関数で『型情報がある可変長引数を受け取りたい』場合などに利用できます。

まとめ

テンプレート自体は突き詰めると『型を引数として渡す機能』だけなので普通に使う分にはそんなに難しくはないと思います。
ただ、C++11/14 でテンプレートを使う場面はかなり増えたので学習コストは上がってきていると思います。
C++03 の頃は敬遠されがちだったテンプレートですが、今は C++ を使う上で必要な技術になりつつあると思います。