おべんきょうのじかんだよ
DにもBoost::Spirit的な何かが欲しいよね、ということで、とりあえず的にExpression Templateでほげほげしたのでした。構文解析とか謎領域なので全く作る気はないのでした。
Expression Templateというのは、簡単にいうと、何でもテンプレート引数に突っ込んでおけばいいじゃん作戦です。
今回は「TypeA + TypeB」のような式の値の型を、「Add!(TypeA, TypeB)」にしたいね、という所からお話は始まります。
とりあえず、TypeAにもTypeBにも同じ演算子オーバーロード関数を持たせたい。同じ関数持たせたいなら、まあOO脳の皆は勿論継承を使うよね!(失礼)というわけでBaseというクラスを作りましょう。
class Base{ Plus!(typeof(this), T) opAdd(T)(T rhs){ return new Plus!(typeof(this), T); } } class TypeA : Base{ } class TypeB : Base{ }
これで「TypeA + TypeB」とかすると、まあ当然「Add!(Base, Base)」になって悲しいわけです。
結局これは、基底クラスから派生クラスの型が知りたいね、と言う話なわけです。
困ったときはテンプレートだ!!テンプレートを使うんだ!!!!
class Base(T){ Plus!(T, U) opAdd(U)(U rhs){ return new Plus!(T, U); } } class TypeA : Base!(TypeA){ } class TypeB : Base!(TypeB){ }
これで解決。めでたしめでたし!
この奇妙な(ボクはそうでもないと常々思っているんですが)テンプレートクラスを自己言及的なテンプレートとか言うそうです。勿論C++ Labyrinthより。
まあこれでも全然問題は無いわけですが。
template ParserBase(){ Plus!(typeof(this), U) opAdd(U)(U rhs){ return new Plus!(typeof(this),U); } } class TypeA{ mixin ParserBase; } class TypeB{ mixin ParserBase; }
どっちがいいか、という話。
たまにはそれらしいことでも書いてみようと思って書いたはいいんですが、ここ見てる人なら皆知ってるよなあというか、まあメモということにしておけば全ては解決します。
あとSpirit的な何かは、多分Dの演算子オーバーロードがへなちょこなので無理です。クリーネスター(*)とか早速無理。
追記:Spritて何。を修正しました。