Traits : C++ template technique
今更ながらC++を学んでいる。単なるOOP機能を備えたCとしてではなくC++固有の機能をもっと活用しようと思ったのがきっかけ。巷ではリーナス・トーバルズ氏のようにC++をボロクソにけなす人達がいるけれど、Cは基本的なデータ構造を扱う標準ライブラリが存在しないのがやはり苦しい。なので、複雑な言語仕様や意味不明なコンパイルエラーに悩みつつも、自分は当分の間 C++を使い続けていくんだろうと思う。
§
最近になって Traits という便利なテクニックを知った。Traitsとは、C++のテンプレート機能を活用してデータ型に関する処理を実行時からコンパイル時に移行させるコーディングテクニック。Traits 自体の説明は C++ Report の過去記事「Traits: a new and useful template technique」が詳しいのでそちらを参照して欲しい。この記事では、STLで採用された様々な実装例を挙げて Traits の導入動機と活用の仕方が詳しく解説されている。
さて、新しく学んだテクニックを応用すべく「Beautiful Code」で紹介されていた正規表現マッチャをC++で書き直してみた。オリジナルとの大きな違いは、ポインタを直接操作する代わりにイテレータを使用している点とワイド文字列に対応した点。このワイド文字列の対応にあたって、次のような re_metachar_trait というクラスを用意した。マッチングの中では、‘*’ や ‘?’ などパターン文字列中のメタ文字を判別する際、文字リテラルを直接指定する代わりに re_metachar_trait のメソッドが返す値を利用している。
template <> struct metachar_trait<char> { typedef char char_type; static char_type hat() { return '^'; } static char_type dollar() { return '$'; } static char_type star() { return '*'; } static char_type plus() { return '+'; } static char_type question() { return '?'; } static char_type dot() { return '.'; } static char_type eos() { return '\0'; } }; template <> struct metachar_trait<wchar_t> { typedef wchar_t char_type; static char_type hat() { return L'^'; } static char_type dollar() { return L'$'; } static char_type star() { return L'*'; } static char_type plus() { return L'+'; } static char_type question() { return L'?'; } static char_type dot() { return L'.'; } static char_type eos() { return L'\0'; } };
このようにデータ型固有の情報を Trait クラスに委ねることで複数のデータ型に対応するための煩雑な条件分岐をマッチング処理から排除することができた。ただし、出来上がったソースコードを眺めてみると余計なキーワードだらけでとても”Beautiful”とは言えない始末。オリジナルコードが本当に美しいのかどうかはともかく、その特徴だった簡潔さが失われてしまってあんまり良い例ではないよね。