Difference between revisions of "Combining structs"
m (pvt) |
m (fix) |
||
Line 9: | Line 9: | ||
}} | }} | ||
− | This recipe is essentially a workaround for the lack of availability of '''''multiple alias this'''''. The code shows how a template ''Gen'' is used to generate a struct '' | + | This recipe is essentially a workaround for the lack of availability of '''''multiple alias this''''' in the current version of the DMD compiler. The code shows how a template ''Gen'' is used to generate a struct ''S_AB'' from structs ''S_A'' and ''S_B''. The template ''Gen'' generates properties and functions within ''S_AB'' with which the fields and functions of ''S_A'' and ''S_B'' can be accessed. [http://dpaste.dzfl.pl/485db6d6 Run the code] |
==Program Code== | ==Program Code== |
Latest revision as of 22:32, 20 January 2013
This recipe is essentially a workaround for the lack of availability of multiple alias this in the current version of the DMD compiler. The code shows how a template Gen is used to generate a struct S_AB from structs S_A and S_B. The template Gen generates properties and functions within S_AB with which the fields and functions of S_A and S_B can be accessed. Run the code
Program Code
import std.traits : isCallable, PIT=ParameterIdentifierTuple, PTT=ParameterTypeTuple;
import std.conv : to ;
import std.algorithm : startsWith ;
import std.array : split ;
template GenStructs(uint count, U...)
{
static if (U.length == 0)
{
enum GenStructs = "\n";
}
else
{
enum GenStructs = "\n private " ~ (U[0]).stringof ~ " _s" ~ to!string(count) ~ ";" ~
GenStructs!(1+count, U[1..$]);
}
}
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..$]);
}
}
}
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 GenFunction(string M, string N, alias SN)
{
enum GenFunction = `
auto ref ` ~ N ~ `(` ~
combine( StringOf!(PTT!(SN)).split(","),
ArgStringOf!(PIT!(SN)).split(",") )~ `)
{ return ` ~ M ~ `(` ~ ArgStringOf!(PIT!(SN)) ~ `); }`;
}
string genProperty(string mem, string name, string s_name)
{
return `static if ( !__traits(compiles, ` ~ name ~ `) )
{ static if (isCallable!(` ~ s_name ~ `.` ~ name ~ `))
{
mixin (GenFunction!( "`~ mem ~`", "`~ name ~`", `~ s_name ~`.`~ name ~`));
}
else
{
@property auto ref ` ~ name ~ `() { return ` ~ mem ~ `; };
@property ` ~ name ~ `(typeof(` ~ s_name ~ `.` ~ name ~ `) _` ~ name ~ `)
{ ` ~ mem ~ ` = _` ~ name ~ `; }
}
}
else
{
}
`;
}
string genAlias(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 = genAlias(count,
Filter!(__traits(allMembers, U[0]))[0..$-1].split(","),
U[0].stringof) ~ GenAliases!(1+count, U[1..$]);
}
}
template Gen(string name, U...)
{
static assert(U.length != 0);
enum Gen = `struct ` ~ name ~ ` { ` ~ GenStructs!(0, U) ~
GenAliases!(0, U) ~ ` }`;
}
///////////////////////////////////////////////////////////////////////////////////
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);
}
Compilation Output
tuple("_s0","_s1","x","y","func","funcA","z","funcB")