Generic structural recursion
H. S. Teoh
hsteoh at quickfur.ath.cx
Wed Jan 26 19:54:35 UTC 2022
On Wed, Jan 26, 2022 at 06:41:50PM +0000, John Colvin via Digitalmars-d wrote:
> On Wednesday, 26 January 2022 at 18:22:18 UTC, H. S. Teoh wrote:
> > [...]
>
> You could define a template that introspects a struct type and gives
> you a tuple of getters (each taking a struct and returning one of the
> doubles), then your functions that do real work would just loop over
> those getters. I suspect using the new(-ish) alias assign feature
> would help in defining that template.
Excellent idea!! Instead of trying to inject some arbitrary function
with multiple arguments into the middle of a recursive traversal, do the
traversal separately at compile-time exclusively on the type, generate
an array of fields, and let the caller loop over them.
Here's the solution I settled on:
--------
string[] eachParam(T)(string prefix = "")
{
string[] result;
if (__ctfe)
{
foreach (field; FieldNameTuple!T)
{
alias F = typeof(__traits(getMember, T, field));
static if (is(F == double))
{
result ~= prefix ~ "." ~ field;
}
else static if (is(F == struct))
{
result ~= eachParam!F(prefix ~ "." ~ field);
}
else static if (is(F == E[n], E, size_t n))
{
foreach (j; 0 .. __traits(getMember, T, field).length)
{
result ~= eachParam!E(text(prefix, ".", field,
"[", j, "]"));
}
}
}
return result;
}
else assert(0);
}
void interpolate(alias ipol = linearInterpolate, T)
(ref T model, double idx, T t1, T t2)
{
static foreach (param; eachParam!T)
{
mixin("model" ~ param) = ipol(idx, mixin("pose1" ~ param),
mixin("pose2" ~ param));
}
}
void nullify(ref T model)
{
static foreach (param; eachParam!T)
{
mixin("model" ~ param) = double.nan;
}
}
// ... and so on
--------
Both parts nice and clean. Well OK, so I used a bunch of mixins. But
they are little self-contained snippets rather than entire function
bodies. That's a win.
T
--
Why ask rhetorical questions? -- JC
More information about the Digitalmars-d
mailing list