テンプレートプログラミングとは文字どおり「テンプレートを使ったプログラミング」のことです.しかし,それだけでは従来のプログラミングとどう違うのか,わざわざ習得するメリットがあるのかどうか,はっきりしません.そもそもテンプレートを使うと,どのようなメリットがあるのか,あるいは問題点が解決されるのか,そこが気になるところでしょう. そこで本章ではテンプレートの基本的な考え方や,テンプレートを使うことで従来のプログラムでは難しかった実装がいかに楽にできるかを説明していきましょう.また本特集で取り上げているSTLやBoostなどの背景としてかかわってくる,ジェネリックプログラミングの考えなども説明します. 同じ記述への対応 プログラミングをするとかならず「似通った記述」や「同じ記述」に出会うものです.たとえば,リスト1のようなC言語でなされたコーディングを見てみましょう.
見るからに要領が悪そうなコーディングがされていますが,すぐに気づくのは, if(x < 0){ という記述パターンと, if(x < y){ という記述パターンが見受けられ,それが鼻につく点です.最初のパターンは「絶対値にする」ですし,次のは「二つのうち大きい値にする」であることがわかります.プログラミングの基本的な戦術として「似通ったパターンや同じパターンがあれば共通化する」があります.難しい言葉が好きな人なら「抽象化」とでも表現するところでしょうか 注1.具体的には, 1)サブルーチンにする あたりがC言語レベルでは常套手段でしょう. 注1:厳密にいうと「共通化」と「抽象化」は別物で,共通化は表面的な類似をまとめてしまう行為なのに対し,抽象化とは本質的なものをまとめてしまう行為を意味する. サブルーチンの導入 さきほどのプログラムで共通する記述パターンはリスト2のような二つの関数にできます.これらを利用して,さきほどのTest()を書き換えるとリスト3のようになります.最初の冗長な記述と比較すると,かなり行数が縮みました.もちろん,ここからさらに行数を縮めることも可能です.サブルーチンを導入することで見通しが良くなり,その結果,さらに見通しを良くするくふうを検討する余地ができました.
マクロの導入 しかし,こんな調子でなんでもかんでも共通部分をまとめられるわけではありません.その理由は“型”の存在です.たとえば,さきほどのTest()がリスト4のように記述されている場合はどうでしょうか.
最初のTest()と似通っていますが,int型で取り扱っていたものが,すべてdouble型に変更されています.ということは,せっかく作ったサブルーチンabs_intもmax_intもそのままでは使えません.型キャストをしても使えません.なぜなら,double型で表現している数値データはint型にキャストされる段階で小数点以下が切り捨てられるので使い物にならないからです. となるとdouble型で使えるバージョンの関数を新たに作るハメになります.たとえば,リスト5のようになるでしょう.
しかしコードを見てわかるとおり,中身はabs_intとmax_intに似ている,というよりまったく同じ代物です.型が違うだけで,すでにある関数が流用できないという情けない状況です. C言語ではこういうときにマクロを使うとよいのはご存知のとおりです.リスト6のようにすればいいわけです.こうしておくとabs_とmax_はint型だろうがdouble型だろうが流用できるはずです. しかし注意しないといけないのは,マクロは単なる文字列の置き換えにすぎない点です.置き換えられた後のソースが期待しているものとかい離する可能性があります.たとえばリスト6のプログラムを縮めて,
a1 = abs_(f()); としたとします.もしもf()が2回以上呼び出したときに同じ値を返さない場合はどうなるでしょうか.この行はプリプロセッサを通過した後は, a1 = (((f()) < 0) ? -(f()) : (f())) となるため,期待した結果にはならないでしょう. また,単なる置き換えであることを十分に意識し,演算子の優先順位にも注意する必要があります.マクロの記述で,やたらにカッコが多いのが目立つのはそのせいです.たとえば,abs_を, #define abs_(X) (X < 0) ? -X : X にしてもいいのではないかと思う人がいるかもしれません.一見問題がないように見えますが,もしも, int a1 = 5; だったらどうでしょうか.この場合,最後の行は, int a3 = (a1+a2 < 0) ? -a1+a2 : a1+a2; と処理され,その結果, int a3 = (5-10 < 0) ? -5-10 : 5-10; となり,a3には期待している5ではなく,−15が入ります. いうまでもなくabs_intやabs_doubleを使った場合は,このような不具合は生じません. マクロは短い記述ですむのであれば便利ですが,長い記述は書くこと自体が苦痛ですし,後から検証やデバッグがやりにくいのも問題です.そのせいかどうかは知りませんが,C言語のキャリアが長い人でも,意外とマクロの使用頻度が少なかったりと,マクロが苦手な人は珍しくありません.
今月号特集トップページへ戻る Copyright 2004 宮坂 電人 |