関数テンプレートを実際に使う際には、どこに、どのように書けばいいのでしょうか。今回はそれについてお話しします。
それでは、今回の要点です。
では、いってみましょう。
何度も言うように、関数テンプレートは「型の違う関数を適宜自動的に作ってくれる」というものです。つまり、定義は1つしかないように見えても、例えば前回の Max では TYPE の異なる関数がいくつも作られることになります。
もし TYPE が int か unsigned int か void* となるような呼び出しを全部行ったとすると、前回の冒頭でやったように3つ関数を作ったのと全く同じことになります。1つの関数で場合分けして処理しているのではなく、それぞれに全く独立した関数を作っているわけですね。
表面上はサイズが小さくなったように見えても、コンパイルしてしまうと思ったよりもサイズが増えることになります。しかし、別々に関数を作ったのでも同じサイズになるので、気にしても仕方はないかも知れませんね。
また、逆に言えば1回も使わなければ Max という関数はどこにも存在しないわけです。Max という関数テンプレートを定義しましたが、あくまでもそれは「鋳型」の定義なのです。実際に使う関数はこの鋳型を使って「鋳造」するわけです。この「鋳造」することを実体化(インスタンス化)と呼び、作られた関数を実体(インスタンス)と呼びます。
また、関数を作るには呼び出したところから実装が見える必要があります。鋳型がなければ鋳物は鋳造できないのです。つまり、TYPE が同じである関数テンプレートの呼び出しのうち、どれか1つは関数テンプレートの実装が見えていなければなりません。
つまり、次のようになるわけです。
// Temp1.cpp // プロトタイプ template <typename TYPE> void Disp(TYPE value); int main() { int a = 0; Disp(a); return 0; } | |
// Temp2a.cpp // 実装 template <typename TYPE> void Disp(TYPE value) { cout << value << endl; } |
// Temp2b.cpp // 実装 template <typename TYPE> void Disp(TYPE value) { cout << value << endl; } // TYPE = int で呼び出す void Dummy() { int b = 1; Disp(b); } |
エラー! | エラー無し |
---|
Temp1.cpp ではプロトタイプしかありません。なので、Temp1.cpp 内では実体化はできません。どこか別のところで実体化されていれば使えますが、どこでも実体化されていないと「実体がない」というリンクエラーが出ます。
Temp2a.cpp では実体化されていないのでリンクエラーになり、Temp2b.cpp では TYPE = int で実体化されているので、リンクエラーにはなりません。
しかし、実体化するためだけに関数を呼び出さなくてはならないのは不便です。そこで、関数を呼ばなくても実体を作ることができます。
// Temp2c.cpp // 実装 template <typename TYPE> void Disp(TYPE value) { cout << value << endl; } // 実体化 template void Disp(int); |
TYPE の部分に具体的な型名を入れたプロトタイプを書き、先頭に template を付ければいいのです。これだけで実体化することができ、リンクエラーは無事出なくなります(注:古いバージョンのコンパイラではできない場合があります)。これを明示的な実体化(インスタンス化)と呼びます。
実際にはこのようなことを考えてプログラムを組むのは不便で汎用性に欠けるので、関数テンプレートの実装は全てヘッダファイルに書きます。こうすれば、いちいち明示的に実体化する必要はなくなります。
「二重定義になるのでは?」と思うかも知れませんが、関数テンプレートはリンクエラーとしての二重定義を起こしません。それは、関数テンプレートは実体の定義ではないからです。そして、作られる実体は型の異なる関数につき1個ずつです。同じ関数が何個もできてしまうということはありません。もしそうなってしまうと同じファイル内で何個も呼び出しをする、つまり実体化をすることができなくなってしまうからです。
ということで、関数テンプレートはヘッダファイルに書くのが普通です。インライン関数や const 定数もそうでしたね。これらはマクロの代替手段として発展したもので、ヘッダファイルに書くのもうなずける話です。
それでは、今回の要点です。
では、次回まで。
Last update was done on 2000.12.6
この講座の著作権はロベールが保有しています