可変個型引数あれこれ

昨日のちょっと修正。

char[] ToString(T1, T2, TA...)(T1 value1, T2 value2, TA values) {
	const char[] delim = ", ";
	char[] buffer = ToString(value1) ~ delim ~ ToString(value2);
	foreach (v; values) {
		buffer ~= delim;
		buffer ~= ToString(v);
	}
	return buffer;
}

あとですねぇ。
可変個型引数を使って型コンテナを実装しようとしたんだが、どーもウマくいかん。

class TypeArray(TA...) {
	const int length = TA.length;
	template typeAt(int n) {
		alias TA[n] typeAt;
	}
}

これでできればサイコーである。シンプルで美しい(自賛)。
だがそーはいかない。

	alias TypeArray!(int, char, double) Types3;
	writefln(typeid(Types3));
	writefln(Types3.length);
	writefln(typeid(Types3.typeAt!(0)));
	writefln(typeid(Types3.typeAt!(1)));
	writefln(typeid(Types3.typeAt!(2)));
...
TypeArray
3
TypeInfo[0]
TypeInfo[1]
TypeInfo[2]

こんな具合。

つまり、ここで言う TA ってのは型の配列ではなく、TypeInfo の配列なのね。欲しいのは型情報ではなく型だ。

納得いかんのでもそっと試してみた。

void testTypes(TA...)(TA values) {
	foreach (v; values) {
		writefln(typeid(typeof(v)));
	}
	writefln(values.length);
	writefln(typeid(typeof(values[0])));
	writefln(typeid(typeof(values[1])));
	writefln(typeid(typeof(values[2])));
}

void main() {
	testTypes(1, 3.14, "ABC");
}
...
int
double
char[3]
3
int
double
char[3]

よかですね。このように型引数ではなく、引数の typeof を取るとウマくいく。
但し、

	writefln(typeid(typeof(values)));

とやると、

Assertion failure: '0' on line 4601 in file 'mtype.c'

となる。

では、型引数の方にアクセスしてみるとどうか?

	writefln(TA.length);
	writefln(typeid(TA));
	writefln(typeid(TA[0]));
	writefln(typeid(TA[1]));
	writefln(typeid(TA[2]));
...
3
TypeInfo
TypeInfo[0]
TypeInfo[1]
TypeInfo[2]

ダメですな。
引数から型を取ることはできるが、型引数からはとれない。

関数テンプレートの場合、型引数だけでなくホントの引数も取るので、関数内で型情報を取れる。
しかし

	alias TypeArray!(int, char, double) Types3;

てった具合に型だけからインスタンス化した場合、テンプレート内で可変個型引数を使って型を取得できない。

可変個型引数は便利だけど、今んとこ威力を発揮すんの関数テンプレートだけだなぁ。
やはり、羅列型で書いたナサケナな TypeArray を再帰を使って書くぐらいが関の山のようである。