import std.traits : isIntegral, isFloatingPoint, isCallable, PIT=ParameterIdentifierTuple, PTT=ParameterTypeTuple; import std.conv : to ; import std.algorithm : startsWith ; import std.array : split ; //import std.stdio : writeln ; template GenStructs(uint count, U...) { static if (U.length == 0) { enum GenStructs = "\n"; } else { enum GenStructs = "\n" ~ (U[0]).stringof ~ " _s" ~ to!string(count) ~ ";" ~ GenStructs!(1+count, U[1..$]); } //pragma(msg, GenStructs); } /* struct test0 { } struct test1(T) { T A; this(T A_) { A = A_; } void setA(T A_) { A = A_; } T getA() { return A; } void empty() { writeln("empty() called"); } ~this() { } } */ //pragma(msg, GenStructs!(0, test0, test1!(int)) ); //pragma(msg, __traits(allMembers, test1!(int))); template Filter(U...) { static if (U.length == 0) { enum Filter = ""; } else { static if ( (U[0]).startsWith("__") || (U[0]).startsWith("op") ) { enum Filter = Filter!(U[1..$]); //skip U[0] } else { enum Filter = U[0] ~ "," ~ Filter!(U[1..$]); } } } //pragma(msg, Filter!(__traits(allMembers, test1!(int)))[0..$-1].split(",") ); template StringOf(TS...) { static if(TS.length == 0) { enum StringOf = ""; } else static if(TS.length == 1) { enum StringOf = (TS[0]).stringof; } else { enum StringOf = (TS[0]).stringof ~ "," ~ StringOf!(TS[1..$]) ; } } template ArgStringOf(TS...) { static if(TS.length == 0) { enum ArgStringOf = ""; } else static if(TS.length == 1) { enum ArgStringOf = TS[0]; } else { enum ArgStringOf = TS[0] ~ "," ~ ArgStringOf!(TS[1..$]); } } string combine(string[] types, string[] members) { assert(types.length == members.length); string combined = ""; for(int i=0; i < (types.length) ; ++i) { combined ~= types[i] ~ " " ~ members[i] ~ ", "; } if(combined != "") combined = combined[0..$-2] ; //trim end ", " return combined; } template GenProperty(string M, string N, alias SN) { enum GenProperty = ` @property auto ref ` ~ N ~ `(` ~ combine( StringOf!(PTT!(SN)).split(","), ArgStringOf!(PIT!(SN)).split(",") )~ `) { return ` ~ M ~ `(` ~ ArgStringOf!(PIT!(SN)) ~ `); }`; //pragma(msg, GenProperty); } string genProperty(string mem, string name, string s_name) { return `static if ( !__traits(compiles, ` ~ name ~ `) ) { static if (isCallable!(` ~ s_name ~ `.` ~ name ~ `)) { mixin (GenProperty!( "`~ mem ~`", "`~ name ~`", `~ s_name ~`.`~ name ~`)); } else { @property auto ref ` ~ name ~ `() { return ` ~ mem ~ `; }; @property ` ~ name ~ `(typeof(` ~ s_name ~ `.` ~ name ~ `) _` ~ name ~ `) { ` ~ mem ~ ` = _` ~ name ~ `; } } } else { } `; } string getAlias(uint id, string[] members, string s_name) { string output; foreach(m ; members) { output ~= genProperty("this._s" ~ to!string(id) ~ "." ~ m, m, s_name); } return output; } template GenAliases(uint count, U...) { static if (U.length == 0) { enum GenAliases = ""; } else { enum GenAliases = getAlias(count, Filter!(__traits(allMembers, U[0]))[0..$-1].split(","), U[0].stringof) ~ GenAliases!(1+count, U[1..$]); } //pragma(msg, GenAliases); } /* struct test2 { int X; int sumX(int val) { return (cast(int)(X + val)); } } */ //pragma(msg, GenAliases!(0, test1!(int), test2) ); template Gen(string name, U...) { static assert(U.length != 0); //otherwise no use for this template enum Gen = `struct ` ~ name ~ ` { ` ~ GenStructs!(0, U) ~ GenAliases!(0, U) ~ ` }`; //pragma(msg, Gen); } //pragma(msg, Gen!("T1", test1!(int))); //mixin (Gen!("T1", test1!(int))); //////////////////////////////////////////////////////////// struct S_A { int x; int y; void func() { x = 2*x; } ; void funcA() { } ; } struct S_B { int x; int z; void func() { x = 3*x; } ; void funcB() { } ; } void main() { import std.stdio: writeln; mixin (Gen!("S_AB", S_A, S_B)); pragma(msg, __traits(allMembers, S_AB)); S_AB s_ab; s_ab.x = 10; s_ab.func(); assert(s_ab.x == 20); }