On 07/08/13 13:25, JS wrote: > mixin template a(T...) > { > template b(TT...) > { > static string eval() > { > string s; > int i = 0; > foreach(t; TT) > s = "@property "~(t).stringof~" Name"~to!string(i++)~"();\n"; > return s; > } > enum b = eval(); > } > > mixin("mixin(b!T);"); > > }
It won't work if one of the types isn't already available inside the template - the .stringof will give you the name, but the mixin will fail; to avoid this you can use `T[0]` etc as the type directly, w/o stringifying. Something like this would also work: template evalExpMap(string C, string F, A...) { enum evalExpMap = { import std.array, std.conv; string s, l; static if (is(typeof(A))) alias B = typeof(A); else alias B = A; foreach (I, _; B) { auto r = replace( replace(F, "%s", A[I].stringof), "%d", to!string(I)); l ~= (I?", ":"") ~ r; s ~= r ~ ";\n"; } return replace(replace(C, "%...;", s), "%...", l); }(); } interface A(T, S...) { mixin(evalExpMap!(q{%...;}, q{@property S[%d]/*%s*/ property%d()}, S)); } class C : A!(int, long, string) { /* Needs `propertyN` implementations. */ } It expands to: interface A(T, S...) { @property S[0]/*long*/ property0(); @property S[1]/*string*/ property1(); } and is more readable (once one knows what that helper does ;) ). In real code, the property names may need to be more configurable; but I'm not sure what you want to use this for. The helper rewrites every "%s" pattern -> type-name and every "%d" -> index; maybe that is enough. artur