またまた文字列
いいかげん、D言語ネタは他にないのかいという感じであるが、またぞろ文字列化関数テンプレートの改良版。
template ToString(T) { char ToString(T value) in { static assert (!(is (T == union))); static assert (!(is (T == function))); static assert (!(is (T == delegate))); } body { static if (is (T : char)) return value; else static if (is (typeof(T.toString))) return value.toString(); else static if (is (typeof(T.init.keys))) return MapToString!( typeof(T.init.keys[0]), typeof(T.init.values[0]) )(value); else static if (is (typeof(T.init)[(T).length])) return StaticArrayToString!(typeof(T.init), (T).length)(value); else static if (is (typeof(T.init.ptr))) return DynamicArrayToString!(typeof(*T.init.ptr))(value); else return std.string.toString(value); } } template ArrayToString(T) { char ArrayToString(T array) { static if (is (typeof(T.init)[(T).length])) return StaticArrayToString!(typeof(T.init), (T).length)(array); else static if (is (typeof(T.init))) return DynamicArrayToString!(typeof(*T.ptr))(array); else return ""; } } template DynamicArrayToString(T) { char DynamicArrayToString(T[ ] array) { char buffer = "["; foreach(T value; array) buffer ~= ToString!(T)(value) ~ ","; buffer = chop(buffer); buffer ~= "]"; return buffer; } } template StaticArrayToString(T, uint N) { char StaticArrayToString(T[N] array) { char buffer = "["; foreach(T value; array) buffer ~= ToString!(T)(value) ~ ","; buffer = chop(buffer); buffer ~= "]"; return buffer; } } template MapToString(Key, T) { char MapToString (T[Key] map) { char[] buffer = "["; foreach(Key key, T value; map) { buffer ~= "("; buffer ~= ToString!(Key)(key); buffer ~= ":"; buffer ~= ToString!(T )(value); buffer ~= "),"; } buffer = chop(buffer); buffer ~= "]"; return buffer; } }
今回の改良点としては、struct や interface も toString メソッドを持っていれば出力可能になった。(interface に toString メソッドを定義することがどんだけ意味あるか知らんが)ただし、toString の型については言及していない。つまり、toString というデータメンバがあるとアウト。
あと、固定長配列にも対応。
int[ ] のインスタンスはもちろん length プロパティを持つが、int[ ]という型自体は length プロパティを持たないのがミソ。また、(T).length のカッコは必要である。
さぁこれでどんな型でも文字列化可能、と言いたいが、int[3][3]を渡すとインスタンス化時にコンパイルエラー発生。
ただしこれは、std.format も同じ問題を抱えている。"%s".doFormat() で int[ ][ ], int[ ][3] は文字列化が可能だが、int[3][], int[3][3] を渡すと、実行時エラーが発生する。
(要するにできないのは私だけではないのだ)
ArrayToString を除けばテンプレート引数がみな違うので、テンプレート識別子と関数名を ToString で統一して、個々の識別はディスパッチまかせにしようかとも思ったが、まぁ意味的にはっきりさせる意味で、名前は分けておいた。
まだ改良の余地ありそう。