テンプレートメタプログラミングが良く解らない

最近は再び C++ を仕事で使い始めています。猫が以前使っていた頃は、たしかまだ namespace もまともに扱えない処理系ばかりだった(いや、これはあたしがモノを知らなかっただけか)し、STLなんて、名前だけしかしらなかったのです。だから、もー、殆ど初めての言語ですよ。
で、どっぷり動的言語の世界に肩まで使った猫にとって、テンプレートを使ったプログラミングはとても楽しいものです。例えば、簡単な基数ソートはこんな感じになります。

/** 基数ソート
 *
 * http://www.tsukuba.jp.hep.net/~masato/
 * link/stdlib/stdug/general/7_3.htm
 * を参考にしました。(というかそのまんま)
 */
void
radixSort(list<unsigned int> & values)
{
  bool flag = true;
  int divisor = 1;

  while (flag)
  {
    vector< deque<unsigned int> > buckets(10);
    flag = false;

    // クロージャモドキを生成
    copyIntoBuckets cpyIntoBkt( divisor, buckets, flag ); 

    for_each(values.begin(), values.end(), cpyIntoBkt);

    accumulate(buckets.begin(), buckets.end(), 
               values.begin(), listCopy);
    divisor *= 10;
  }
}

ソートのコア部分はここまで。後はクロージャモドキを実現する関数オブジェクトと、acuumulate で利用する listCopy を実装してあげる必要があります。

/** バケットにリストの中身をコピーする
 *
 *  クロージャが使えないので代わりに
 *  オブジェクトを使う。(callable にするために
 *  ()演算子をオーバロードする)
 */
class copyIntoBuckets
{
public:
  // コンストラクタでコンテキスト変数を取り込む
  copyIntoBuckets
    (int div, vector< deque<unsigned int> > & bkt, bool & flg) 
    : divisor(div), buckets(bkt), flag(flg) {}

  int divisor;
  vector<deque<unsigned int> > & buckets;
  bool & flag;

  // 関数オブジェクトにするため () をオーバロード
  void operator () (unsigned int value)
  {
    int index = (value / divisor) % 10;

    if (index){
      flag = true; 
    }
    buckets[index].push_back(value);
   }
};

/** リストを元のリストにコピーし、終端に戻る
 */
list<unsigned int>::iterator 
listCopy(list<unsigned int>::iterator c, 
         deque<unsigned int> & lst)
{
   return copy(lst.begin(), lst.end(), c);
}

素敵♪ 実はこれ、100% 猫のコードと言うわけじゃなくって、http://www.tsukuba.jp.hep.net/~masato/link/stdlib/stdug/general/7_3.htmさんから拝借したコードにちょっとだけ手心を加えたモノ。猫はまだこんなにSTLを理解していませんが、モノにしたいと思わせるコードじゃありません?(Boostを使えばlambdaも直接つかえるしっ!)

ただ、ちょっとばかし疑問におもうのです。うーん、、テンプレートってダッグ・タイピングよねぇ。

暗黙のインターフェイスが欲しいなら

Effective C++ 第3版の 41項のタイトルはズバリ 「暗黙のインターフェイスコンパイルポリモーフィズムを理解しよう」 です。テンプレートを使ったメタプログラミングとは、即ちコンパイル時の動的型付けとポリモーフィズムです。

暗黙の型、つまり「どのように操作できるか」のみが頼りのダッグ・タイピングは嬉しいから、 C++ でこれが出来るのは良いことです(特に猫にとっては!)。但しこれはアクマで「コンパイル時の」動的型付けなので、そうは言っても実行時はちゃんと静的型付けだよ、おいしいとこ取りだよというわけです。

・・・と、ここまでは猫の小さな脳みそでも理解できるのですが、なんでこれが嬉しいのかが理解できてないです。なんでこんな七面倒くさいことをするのかなぁ、全部動的型でいいじゃん

継承に依存しないポリモルフィズムを使いたいだけなのにメタなプログラミングになっちゃう。これは「嬉しい」のかしら?

いあいあ、もちろんあたしの理解が全然足りてないせいなのは解るのです。全く的はずれなこと言ってるんじゃないかなぁ、という雰囲気がぷんぷん漂っているのは感じますし(^^;)、しらないから知ってる事の範囲でケリをつけようとしてるのかも。ともかく理解できてないからこそ この辺がスッキリ来てないのです。

むーっ、知見を広げるチャンスだわね、こりは。