C++では関数を定義する際に引数や戻り値の型を明示する必要があり、引数や戻り値の型や個数が異なる関数は異なる関数として扱われます。しかし、型がintとdoubleの差だけなのに関数を別で定義するのは面倒だし、移植の際のエラーの原因にもなります。そこで、C++ではテンプレート関数というものが用意され型を動的に変更して実行できる関数(テンプレート関数)を作成することができます。本記事ではテンプレート関数について紹介します。
テンプレート関数の基本
まずは基本的なテンプレート関数の使い方を説明します。
テンプレート関数の書き方
テンプレート関数は次のように定義することができます。
タイトル:main.cpp
template <class Type> Type add(Type a, Type b){ Type result = a + b; return result; }
まず、template <class Type>
と記述し、Typeというテンプレート仮引数を用いてテンプレート関数を作成するよと宣言します。テンプレート仮引数とは関数の実行時にintやdoubleなど動的に決定したい型の変数を関数内で宣言する際に用いるものです。Typeという文字は任意なので、別の名前をつけることもできます。
関数の定義部分については普通の関数とほとんど同じで、動的に決定したい変数の部分を先ほど宣言した、Typeで置き換えるだけです。非常に簡単ですね。
テンプレート関数の使い方
先ほど定義したテンプレート関数は次のように使用することができます。
タイトル:main.cpp
#include <iostream> template <class Type> Type add(Type a, Type b){ Type result = a + b; return result; } int main(){ int x_i = 45; int y_i = 55; double x_d = 4.5677; double y_d = 78.4456; std::cout << add(x_i, y_i) << std::endl; //int型の足し算 std::cout << add(x_d, y_d) << std::endl; //double型の足し算 }
タイトル:実行結果(main.out)
$ ./main.out 100 83.0133
main関数内でint型とdouble型の両パターンについてそれぞれの型で計算がされ結果が返ってきます。では次のようなパターンの場合どうなるでしょうか?
タイトル:main.cpp
int x_i = 45; double y_d = 78.4456; std::cout << add(x_i, y_d) << std::endl;
add()の引数にint型とdouble型の引数を入れてみました。これだとどちらの方で計算をすれば良いのか分からなくなります。したがって、コンパイル時にコンパイルエラーが発生します。そこで次のように明示的に型を指定することでどの型を用いるのかを明確にします。
明示的に型を指定する
タイトル:main.cpp
int x_i = 45; double y_d = 78.4456; std::cout << add<int>(x_i, y_d) << std::endl; std::cout << add<double>(x_i, y_d) << std::endl;
このように<>を用いて型を明示します。それだけでいいのです。ただし、int型を明示した際にはy_dのdouble型の値はキャストされて、78として扱われることに注意しなくてはなりません。
タイトル:main.cpp
#include <iostream> template <class Type> Type add(Type a, Type b){ Type result = a + b; return result; } int main(){ int x_i = 45; int y_i = 55; double x_d = 4.5677; double y_d = 78.4456; std::cout << add<int>(x_i, y_d) << std::endl; std::cout << add<double>(x_i, y_d) << std::endl; }
タイトル:実行結果(main.out)
$ ./main.out 123 123.446
ここまでで基本的な使い方について扱いましたが、特定の型の時にだけ別の処理を行いたい場合は明示的に特殊化を行うことで対応できます。次項ではその方法について紹介します。
明示的な特殊化を行う(応用)
先ほどのadd()において、std::string型の引数を取った場合にはスペース区切りで文字を連結させようと思います。この場合は次のようなテンプレート関数を定義します。
タイトル:main.cpp
template <> std::string add(std::string a, std::string b){ std::string result = a + " " + b; return result; }
上記のようにtemplate <>
と宣言し、指定したい型の関数(上記ではstd::string型)を記述します。これを用いることで、add<std::string>()
の場合は上記の関数が実行されます。以下が実行例です。
タイトル:main.cpp
#include <iostream> template <class Type> Type add(Type a, Type b){ Type result = a + b; return result; } template <> std::string add(std::string a, std::string b){ std::string result = a + " " + b; return result; } int main(){ int x_i = 45; int y_i = 55; double x_d = 4.5677; double y_d = 78.4456; std::string x_str = "ほげ"; std::string y_str = "ふが"; std::cout << add(x_i, y_i) << std::endl; std::cout << add(x_d, y_d) << std::endl; std::cout << add<double>(x_i, y_d) << std::endl; std::cout << add(x_str, y_str) << std::endl; }
タイトル:実行結果(main.out)
$ ./main.out 100 83.0133 123.446 ほげ ふが
上から順に、
- 引数がint型なのでint型で実行
- 引数がdouble型なのでdouble型で実行
- 引数はint型とdouble型だが、double型を明示しているのでdouble型で実行
- 引数がstd::string型なのでstd::string型の関数を実行
となります。確認してみてください。
この記事のまとめ
本記事ではテンプレートを用いた関数の定義方法と使用方法について解説しました。最後にこの記事の内容をまとめておきます。
- テンプレート関数を用いることで引数に応じた型の違う関数を定義することができる
- 引数だけで曖昧な場合は<>を用いて使用時に明示的に指定する
- 特定の型だけで実行したい場合は特殊化をした関数を定義する
code-databaseではC++に関する記事を続々作成中です!参考になれば嬉しいです!