private import std.stdio, std.string; private template TupleMultiMix(A, B) { private A head; static if (is(B == void)) { const static bool lastNode = true; } else { const static bool lastNode = false; } static if (!lastNode) { private mixin TupleMultiMix!(B.HeadType, B.TailType) tail; } static if (lastNode) { const static uint length = 1; } else { const static uint length = tail.length + 1; } template val(uint x) { static if (x >= length) { static assert(x < length, "Tuple index out of bounds"); } else static if (0 == x) { alias head val; } else { alias tail.val!(x-1) val; } } char[] toString() { return "[" ~ toStringImpl ~ "]"; } private char[] toStringImpl() { static if (is(typeof(head.toString))) { char[] res = head.toString; } else { char[] res = std.string.format(head); } static if (!lastNode) { return res ~ ", " ~ tail.toStringImpl(); } else { return res; } } } struct Tuple(A, B = void) { alias A HeadType; alias B TailType; mixin TupleMultiMix!(HeadType, TailType); } template List(A, B) { alias Tuple!(A, Tuple!(B)) List; } template List(A, B, C) { alias Tuple!(A, Tuple!(B, Tuple(C))) List; } template List(A, B, C, D) { alias Tuple!(A, Tuple!(B, Tuple!(C, Tuple!(D)))) List; } /+ ... could go on with List specializations +/ // for testing purposes only struct Foo { int a, b; static Foo opCall(int a, int b) { Foo res; res.a = a; res.b = b; return res; } char[] toString() { return "Foo(" ~ .toString(a) ~ ", " ~ .toString(b) ~ ")"; } } void main () { { List!(int, float, char, double) a; writefln(typeid(typeof(a.val!(0)))); writefln(typeid(typeof(a.val!(1)))); writefln(typeid(typeof(a.val!(2)))); writefln(typeid(typeof(a.val!(3)))); writefln("length: ", a.length); a.val!(0) = 2; a.val!(0) *= 123; a.val!(1) = 2.1f; a.val!(2) = 'a'; a.val!(3) = 6.4; writefln(a.toString); writefln(); } { List!(int, float, char, double) a; writefln(typeid(typeof(a.val!(0)))); writefln(typeid(typeof(a.val!(1)))); writefln(typeid(typeof(a.val!(2)))); writefln(typeid(typeof(a.val!(3)))); writefln("length: ", a.length); a.val!(0) = 1; a.val!(0) *= 147; a.val!(1) = 345.24f; a.val!(2) = '@'; a.val!(3) = 3.14159; writefln(a.toString); writefln(); } { Tuple!(char[], Tuple!(bool, Tuple!(Foo, Tuple!(int[])))) b; writefln(typeid(typeof(b.val!(0)))); writefln(typeid(typeof(b.val!(1)))); writefln(typeid(typeof(b.val!(2)))); writefln(typeid(typeof(b.val!(3)))); writefln("length: ", b.length); b.val!(0) = "foobar"; b.val!(1) = true; b.val!(2) = Foo(256, 11111); b.val!(3) ~= 3; b.val!(3) ~= 5; b.val!(3) ~= 7; writefln(b.toString); writefln(); } { Tuple!(char[], Tuple!(cdouble)) c; writefln(typeid(typeof(c.val!(0)))); writefln(typeid(typeof(c.val!(1)))); writefln("length: ", c.length); c.val!(0) = "hahaha"; c.val!(1) = 2 + 1i; writefln(c.toString); writefln(); } { List!(List!(int, int), List!(int, int)) m; writefln(typeid(typeof(m.val!(0)))); writefln(typeid(typeof(m.val!(1)))); writefln("length: ", m.length); m.val!(0).val!(0) = 0; m.val!(0).val!(1) = 1; m.val!(1).val!(0) = 2; m.val!(1).val!(1) = 3; writefln(m.toString); writefln(); } getchar(); }