C++テンプレートメタプログラミング(MPL)とは? †テンプレートメタプログラミングとは、C++のテンプレート(template)を使って、コンパイル時に様々な処理を行ってしまうテクニックです。 テンプレートメタプログラミングのメリット †
テンプレートメタプログラミングのデメリット †
テンプレートメタプログラミングの例 †簡単な例をいくつか紹介します 配列のサイズを得る †配列のサイズを計算するには、#defineマクロとsizeof演算子でも可能です。 #define CountOf(x) (sizeof(x) / sizeof(x[0])) int hoge[100]; printf("%d", CountOf(hoge)); これで"100"がプリントされます。これをテンプレートを使って実装すると、 template <typename T, size_t N> size_t CountOf(const T(&)[N]) { return N; } こうなります。"int hoge[100]"のような単純な配列を与えれば差はありませんが、配列以外のものを渡した場合、#defineだと無条件にエラーになってしまいます。 テンプレートを使えば配列以外の型にも対応が可能なのです。たとえば、STLのコンテナのようなsize()で個数を得られるものに対応するには、 template <typename T> size_t CountOf(const T& container) { return container.size(); } これでOKです。#defineでは同名でオーバーライドできませんし、テンプレートを使ったほうがスマートですよね。 条件によって変数の型を変える †if_c <[条件], [真の場合], [偽の場合]> この"if_c"を使って、要素が固定されているデータ配列があり、通常はstd::vector<>を使って実装したいが、要素が1個の場合は単独の定義としたいというHogeClassの実装を行ってみます。 template <size_t N, typename DataType> struct HogeClass { typedef if_c<N==1, DataType, std::vector<DataType> >::type type; }; 例: HogeClass<1, std::string>::type singleString; HogeClass<5, std::string>::type vectorString; if_cの定義 template <bool C, typename T, typename F> struct if_c { typedef T type; }; template <typename T, typename F > struct if_c<false,T,F> { typedef F type; }; タイプリスト †STLのlistのように、「型」のリストを扱うMPLです。boostにもちゃんとしたlistがありますが、これは概念を理解するための簡易版です。 // NULLクラスの定義 class NullType {}; // タイプリスト template <typename T, typename U> struct Typelist { typedef T Head; typedef U Tail; }; // タイプリスト定義用のマクロ template <typename T1, typename T2, typename T3 = NullType , typename T4 = NullType , typename T5 = NullType , typename T6 = NullType , typename T7 = NullType , typename T8 = NullType > struct list { typedef Typelist<T1, Typelist<T2 , Typelist<T3 , Typelist<T4 , Typelist<T5 , Typelist<T6 , Typelist<T7 , Typelist<T8, Typelist<NullType, NullType> > > > > > > > > type; }; // begin, end, next, derefなどの実装 template <typename Cnt> struct f_ite { typedef typename Cnt::Head type; typedef f_ite<typename Cnt::Tail> next; }; template <typename Cnt> struct begin { typedef typename f_ite<Cnt> type; }; template <typename H, typename T> struct endL { typedef typename endL<typename T::Head, typename T::Tail>::type type; }; template <typename T> struct endL<NullType, T> { typedef Typelist<NullType, T> type; }; template <typename Cnt> struct end { typedef typename f_ite<typename endL<typename Cnt::Head, typename Cnt::Tail>::type > type; }; template <typename Ite> struct next { typedef typename Ite::next type; }; template <typename Ite> struct deref { typedef typename Ite::type type; }; 使用例 typedef list<ImageBufferRGBA, ImageBufferRGB, ImageBufferGRAY>::type ImageTypeList; typedef begin<ImageTypeList>::type ImageTypeListBegin; typedef end<ImageTypeList>::type ImageTypeListEnd; template <typename Begin, typename End> struct ExecuteImageProcT { typedef typename deref<Begin>::type Type; template <class Proc> static void execute(Proc proc, uint32_t fmt) { if (Type::PixelFormatType == fmt) { proc.execute<Type>(); } else { ExecuteImageProcT<next<Begin>::type, End>::execute<Proc>(proc, fmt); } } }; template <typename End> struct ExecuteImageProcT<End,End> { template <class Proc> static void execute(Proc , PixelFormat) { }; }; // ここからが使用例 void hoge(uint32_t format) { struct Proc { tempalte <typename ImageType> void execute() { ImageType img; // hogehoge } } ExecuteImageProcT<ImageTypeListBegin, ImageTypeListEnd>::execute(Proc(), format); } これは、ImageBufferXXXXといういくつかのタイプのイメージバッファのリストから、PixelFormatType というピクセルの型が一致した場合に何らかの処理を行わせるものです。このように、型のリストから動的にオブジェクトを生成するなどの処理ができます。これをうまく使うと、virtualを使わずに仮想的な多様性を持たせる事ができます。 [ 戻る ]
|