Modern C++ Design(これは古い日記です)
この日記はC++の素晴らしさを啓蒙するのが目的なので、Modern C++ Designのことを書かなければならない。Modern C++ Designで紹介されているテクニックはあまりに凄すぎて、現在の俺にはその凄さを説明できるだけの能力がないので、概要説明程度しかできないが。というかまだはじめの方だけしか読んでないし。
Modern C++ Designは、C++によるテンプレートメタプログラミングについて解説された、現在日本語で読める唯一の本である。現在「テンプレートメタプログラミング」というパラダイムを扱える言語は、おそらくC++とDだけである。(Dでも多分できると思うが、Dはよく知らない。)ここら辺が、JavaやC#がどうあがいてもC++を越えられない部分である。
以前の日記に書いたように、C++にはtemplateというものがある。
これはvector
通常のプログラミングでは、実行時に値を操作することを主な目的とするが、コンパイル時のプログラミングでは、値ではなく、型を操作するプログラミングが行える。
Modern C++ Designに紹介されている例では、
template <int v> struct Int2Type { static const int value = v; // 本では enum { value = v }; とあるが、同じ }; template <typename T> struct Type2Type { typedef T OriginalType; };
というものがある。これは、テンプレートパラメータを変更することによって、コンパイル時に新たな型を作り出すものである。
Int2Type<10>、Int2Type<99>、Type2Type
Modern C++ Designでは、これを応用したTypeListという概念を用いている。TypeListとは、基本的には
template<typename T, typename U> struct TypeList { typedef T Head; // Lisp の car typedef U Tail; // Lisp の cdr };
これを組み合わせただけのものだ。これはLispでいうところのconsセルに当たる。TypeListは文字通り「型のリスト」であり、俗にいう線形リスト、Lispでいうところのリストと同じようなものだが、普通のリストが「値のリスト」であり、プログラムの実行時に操作対象となるのに対し、この「型のリスト」は、コンパイル時に操作される。
TypeListは、Lisp でいうところの、cons, car, cdr, append といった、基本的なリストの生成、分解、結合機能を持つ。コンパイル時にテンプレートを用いた再帰によって、型を保持するだけのリストを、組み立てたり分解したりできるわけだ。
ただし、Lispでいうところの(a b c)というリストは、TypeList > >のようになってしまうので、やむを得ずTYPELIST_3(a, b, c)といったマクロに頼ることになる。Cプリプロセッサのマクロを排除することを1つの目的としているtemplateが、その機能を最大限に生かそうとしたときにマクロに頼らざるを得ないというのは、何とも皮肉な話であるが。
TypeListを用いると、リストに列挙された型を実体化する、といった操作が可能となる。
Modern C++ Design では、GenScatterHierarchy、GenLinearHierarchyという基本的なクラス階層構築用ツールにTypeListを用いている。
GenScatterHierarchyは「拡散継承階層」を生成する。具体的には、
「型のリストをcarとcdrに分解して、car部分と、「cdr部分をcarとcdrに分解して再帰的に多重継承したもの」の、2つを多重継承することによって、最終的に型のリストの要素、全てを多重継承する」ということを行う。
template <typename T> struct Holder { T value; }; typedef GenScatterHierarchy<TYPELIST_3(Foo, Bar, Baz), Holder> Hoge;
とした場合、HogeはHolder
GenScatterHierarchyによって、任意の型の値を組み合わせたクラスを作成できる。上の例では、Foo, Bar, Baz型の変数をメンバとして持つクラスが生成できる。
GenLinearHierarchyは、「線形継承階層」を生成する。具体的には、
「型のリストをcarとcdrに分解して、「cdr部分を再帰的にcarとcdrに分解しつつ、car部分はcdr部分を継承」したものをcar部分で継承することによって、最終的に型のリストの全ての要素を単一継承階層に組み込む」ということを行う。(日本語で説明すると難解だが、元のコードはもっと難解である)
typedef GenLinearHierarchy<TYPELIST_3(Foo, Bar, Baz), EventHandler> Hoge;
とした場合、(派生クラス)Hoge => EventHandler
とりあえず、これを理解するのに2時間くらいかかった。ここには具体的なコードを示していないが、再帰的にテンプレートが実体化されつつ、テンプレートパラメータが再帰的に展開され、継承される、というコードは慣れていない人間には難解過ぎる。
Modern C++ Designは日本で2001年に出版された本なので、結構古いのだが、この本で紹介されている機能は、先進的すぎるのか、難解すぎるのか、(そもそも必要とされていないからだと思うが、)あまり世の中に浸透していないように思う。
将来仕事で使えるくらい広まらないかなあ、とか思っていたが、もしそんなことになれば、俺が理解できずにDrop Outしそうだとも思った。
というわけで、Modern C++ Designは非常に素晴らしい(マニアックな)本なので、みんな読みましょう。