第31章 冶金工場

 今回から数回にわたってテンプレートというものについて話します。テンプレートを日本語にすると「鋳型」です。さて、どんな機能なのでしょうか。


 今回の要点は次のようになっています。


 では、いってみましょう。


 早速ですが次のマクロを見て下さい。

// 大きい方の値を返すマクロ
#define MAX(a, b)   ((a) > (b) ? (a) : (b))

 このマクロに特におかしな所はありません。しかし、これがマクロであるがための欠点というものがあります。

 それは関数の感覚で MAX(i++, j) としてしまったときにおかしくなる ことです。これは ((i++) > (j) ? (i++) : (j)) と展開され、もし i が j よりも大きかった場合 i が2回インクリメントされてしまいます。しかも返される値は当初の i の値+1です。もし MAX が関数なら、このようにしても返されるのは i の値だし、i のインクリメントは1回だけです(第3部第7章参照)。

 ここではインクリメントを例にしましたが、ここに関数を入れたのでも構いません。その際、関数は2回も呼ばれてしまいます。このマクロ特有のバグは見つけにくく、第1部第30章の最後に話した「もう1つの重要なバグ」です。

 かといって安全のため MAX を関数にすると、いろいろな型に対する Max を作らなければならなくなります。それは不便です。

 あと、もう1つマクロには引数の型をチェックしないという欠点があります。次のマクロを見て下さい。

// 指定した型で比較し、大きい方の値を返すマクロ
#define TMAX(type, a, b)   ((type)(a) > (type)(b) ? (type)(a) : (type)(b))

 確かにこれで比較は行えます。しかし、a や b が本当に指定した型でキャストしていい型なのかはチェックされず、強引にキャストされてしまいます。例えばアドレスの比較をしたいと思って

p = TMAX(void*, str, num);

としたとします。p の型は void* 、str の型は char* 、num の型は int とします。

 見ると分かると思いますが、アドレスを比較するというのに num に & を付け忘れています。しかし、int から void* へのキャストは可能なので、エラーは出ません。これが void* の引数をとる関数ならエラーになりますが、その場合はやはり型毎に別々の関数を作らなければなりません。


 結局、MAX は関数で作るべきだが、いろいろ型の違う関数をいちいち作らなくてはならないので面倒だ、ということになります。


 そこで、C++には1つの定義を書いただけで型の違う関数を適宜自動的に作ってくれるような機能があります。それを関数テンプレートと呼びます。

 テンプレートは「鋳型」という意味で、関数テンプレートはいろいろな型の関数を作るための鋳型のようなものです。例えば、次の関数を見て下さい。

// 大きい方の値を返す関数テンプレート
template <typename TYPE>
TYPE Max(TYPE a, TYPE b)
{
    return (a > b) ? a : b;
}

 先ず、関数定義の直前template <typename TYPE> というものが付いています。そして、戻り値、引数のがさっき書いたものの中にあった TYPE になっています。

 これが関数テンプレートです。ここで int 型変数 a, b を使って Max(a, b) とすると TYPE の部分が int になった関数が作られ、そして呼ばれます。そして char 型変数 c, d を使って Max(c, d) とすると TYPE の部分が char になった関数が作られ、呼ばれます。

 つまり、状況を自動的に判断し、それに合った型の関数を自動的に作ってくれるのです! TYPE で書かれたところには全て同じ型が割り当てられるというわけです。


 今回は何となく使い方を話すだけにして、これで終わりにします。細かい文法的なことは次回に回します。次回を読む前にいろいろと推察してみるのもいいでしょう。

 では、今回の要点です。


 それでは、また次回まで。


第30章 静かなるメンバ3 | 第32章 冶金工場2

Last update was done on 2000.12.6

この講座の著作権はロベールが保有しています