import std.stdio; template Declare(T) { T Declare; } struct Empty {} template TupleType(A = Empty, B = Empty, C = Empty, D = Empty, E = Empty, F = Empty, G = Empty /*,...*/) { static if (is(A == Empty)) alias Empty TupleType; else alias List!(Dynify!(A),.TupleType!(B,C,D,E,F,G/*,...*/)) TupleType; } template Tuple(A = Empty, B = Empty, C = Empty, D = Empty, E = Empty, F = Empty, G = Empty /*,...*/) { TupleType!(A,B,C,D,E,F,G /*,...*/) Tuple(A a = Init!(A), B b = Init!(B), C c = Init!(C), D d = Init!(D), E e = Init!(E), F f = Init!(F), G g = Init!(G) /*,...*/) { static if (is(A == Empty)) return Empty.init; else return List!(Dynify!(A),TupleType!(B,C,D,E,F,G/*,...*/))(a,.Tuple(b,c,d,e,f,g /*,...*/)); } } struct List(A,B) { A head; B tail; static List opCall(A a, B b) { List!(A,B) ret; ret.head = a; ret.tail = b; return ret; } } template Dynify(T) { static if( is(typeof(Declare!(T)[0]) E)) static if (is(T:E[])) alias E[] Dynify; else alias T Dynify; else alias T Dynify; } template Init(T) { const T Init = void; } template decl_vararg_func(alias realFunc) { template decl_vararg_func(A = Empty, B = Empty, C = Empty, D = Empty, E = Empty, F = Empty, G = Empty /*, ...*/) { typeof(realFunc(Declare!(TupleType!(A,B,C,D,E,F,G/*,...*/)))) decl_vararg_func(A a = Init!(A), B b = Init!(B), C c = Init!(C), D d = Init!(D), E e = Init!(E), F f = Init!(F), G g = Init!(G) /*,...*/) { return realFunc(Tuple(a,b,c,d,e,f,g /*,...*/)); } } } template funcImpl(T) { void funcImpl(T args) { static if (is(T == Empty)) { writefln("Done!"); } else { writefln("Got argument: (%s) %s",typeid(typeof(args.head)),args.head); .funcImpl(args.tail); } } } alias decl_vararg_func!(funcImpl) func; template funcImpl2(T) { int funcImpl2(T args, int n = 0) { static if (is(T == Empty)) { writefln("funcImpl2 called with %s argument(s)",n); } else { .funcImpl2(args.tail, n+1); } return 5; } } alias decl_vararg_func!(funcImpl2) func2; void main() { func(1,5.6,3L,"test"); writefln("func2() = ",func2()); func(null); func("test","test2",3); }