C++の template をもっと勉強すべきか

dynamic cast が使えない環境で Scheme VM の内部オブジェクト(Integer, UCS4Char,String, Regexp,Pair)を C++ のテンプレートを駆使してうまく(パフォーマンス良く、安全に)構築できないか考えたが思い浮かばない。
関数テンプレートもクラステンプレートも普段あまり使わないのがまずいのかもしれない。


何も考えないならば以下の方法をとると思う

  • Baseクラス Object を継承
  • 各クラスは typeid() 的な定数を返す
  • オブジェクトを扱う関数(例えば dump) は dump(Object* o) のように Object* を引数にとる
  • 必要な場面で typeid() を参照し (String*)o のようにキャストされて使われる


しかしメモリ効率や速度を考えると、Integer, UCS4Char あたりは即値として扱いたくなる。
どういうことかというと Object* o の実体が Integer と分かっているなら
Object* o そのものに Integer としての値が入っているということ。
例えばタグとなる下位2bit を除いて 30bit値とか。 (int)(o >> 2) して取り出す。


ただしこの方法をとると Base クラスとか言ってられなくてC++のクラスは「直接は」使えなくなる。
おおざっぱに言うと Regexp も String も先頭が同じ構造の構造体を利用して表現する。

struct BaseObject {
  int tag;
};

struct RegexpObject {
  int tag;
  ... 以下 Regexp 固有
};
struct StringObject {
  int tag;
  ... 以下 String 固有
};

このようにしておけば、Stringであろうと、Regexpであろうと ((BaseObject*)o)->tag として typeid 的なものを取り出せる。
当然 Integer の可能性もあるのでまず先に o の下位ビットを見て、なんらかのフラグビットが立っていたら Integer と判断する。
Heapに確保されたものは、適切にalign されるようにしておけば、フラグビットは絶対ゼロになるようにできるし。


これら2個の手法の良いとこ取りをした方法が template で実現出来るのではないかと、もやもやしていろいろ実験してみたがなかなかうまくいかない。
もし良いアイデアや既存の実装を知っていたらぜひ教えてください。


気づけば言語処理系のデータ型定義の解説になっているような。。