Imaginary Template Metaprogramming in D
D言語を使って脳内でメタプログラミングして遊んでみる(コンパイルできる環境が手元にないので想像)。本当にただの妄想なので、そこのところは了承してちょんまげ。
template Tuple(xs...) { alias xs Tuple; }
いつの間にかPhobosから削除されていたけど、これがないと不便。
template Foldr(alias f, alias init) { alias init Foldr; } template Foldr(alias f, alias init, alias x, xs...) { static if (xs.length != 0) alias f!(x, Foldr!(f, init, xs)) Foldr; else alias f!(x, init) Foldr; } template Foldl(alias f, alias init) { alias init Foldl; } template Foldl(alias f, alias init, alias x, xs...) { static if (xs.length != 0) alias Foldl!(f!(init, x), xs) Foldl; else alias f!(init, x) Foldl; }
コンパイルタイムfold。
どうせならFoldl!((T, U) { ... }, x, xs)みたいにtemplateリテラル書きたいなぁ、となる。なんかデリゲートテンプレートリテラルはあるらしいけど。でも無名なtemplateがあったりしたら、そのメンバの名前を省略できなくて悲しい、なんかないのか…いや、そこはC++式にtypeメンバを用意するとかでいいのかも知れないけど。
struct Pack(xs...) {};
別のタプルを二つ以上引数に取りたいときどうすればいいかなぁ…と思って考えてみた。型にすればいけるんじゃね?というわけで、
template Foo(T : Pack!(xs).Pack, U : Pack!(ys).Pack, xs..., ys...) {}
なんかこんな感じに書けて、Foo!(Pack!(int, char), Pack!(double, float))と書けばxs, ysが勝手に求まってほしいんだけど、まぁ知らん。私が調べた限りでは、一度に複数のテンプレートパラメータを決定することはできるっぽいし、TemplateTupleParameterを二つ以上書くことは禁止されていない。
せめてtemplate Foo(T : Pack!(xs).Pack, xs...)とかはできてほしいというか、これができないとか何なの?ってなる。
あと一応 .Pack まで書いたけど、いらんのかどうかは知らん。
template Zip(T : Pack!(), U : Pack!()) { alias Tuple!() Zip; } template Zip(T : Pack!(x, xs), U : Pack!(y, ys), x, xs..., y, ys...) { alias Tuple!(Pack!(x, y), Zip!(Pack!(xs), Pack!(ys))) Zip; }
TとUを与えてx, xs, y, ysが自動推論されるなら、こんな感じにZipを書ける。
template AddReference(T) { alias typeof(ref typeof(T.init) function() { return T.init; } ()) AddReference; }
refが型の一部で、typeof(f())が、f()の戻り値の型そのままを示すのであれば、AddReferenceメタ関数は書ける。ref Tというのは関数のパラメータの型か戻り値の型にしか書けないらしいので、こんなややこしい書き方になった。
template Foo(alias x, xs...) { alias x Foo; } alias Tuple!(int, int, int) tup; alias Foo!(int, int, int).x test1; alias Foo!(Tuple!(int, int, int)).x test2; alias Foo!(tup).x test3;
って書いたとき、私としてはtest1〜3は全て同じ結果になってほしいのだけど、どうなんだろう…
test1はまぁintになると思うけど、test2の場合、alias xにTuple!(int, int, int)が丸ごとセットされるのか、test1みたいにタプルが解体されて、xがintでxsが残り全部、みたいになるのか。TemplateAliasParameterの説明にはTemplateInstanceを引数に取れるとは書いてないけど、global nameにTemplateInstanceが含まれるかもしれないから(C++ルールでは)、test2はintなの?それともTuple!(int, int, int)なの?test3の場合、引数は明らかにtemplate alias nameなので、結果はTuple!(int, int, int)にならないとおかしい。でもaliasかそうでないかで挙動が変わるのは不審すぎるし、このあたりの挙動が分からんなぁ…Exceptional DとかEffective Dとか出たら間違いなく槍玉にあげられるレベルでやばい。
まぁ細かいことは実装=規格ということでいいんだろうけど、それだといつまでたっても規格決まらないじゃない!遊びにくいですわよ!
で、また思ったんだけど、別に毎回毎回特殊化でパターン書いて判別しなくても、
template Unpack(T : Pack!(xs), xs...) { alias xs Unpack; }
というのさえ私の意図した通りになってくれればUnpack!(tup)だけで済むので、それはそれでいいんじゃなかろうかと思う。
あとtemplate Foo() { template Foo() { alias int x; } }みたいに、あるテンプレートのすぐ内側に同じ名前のテンプレートが定義できるのだろうかというのも分からん。できたからと言って面白いことができるとか、そういうのは知らん。