On 1/26/22 1:22 PM, H. S. Teoh wrote:
>X interpolate(X)(ref X result, double idx, X data1, X data2) {
foreach (field; FieldNameTuple!X) {
alias Type = typeof(__traits(getMember, X, field));
if (is(Type == double))
__traits(getMember, result, field) =
(1.0-idx)__traits(getMember, data1, field)
+ idx__traits(getMember, data2, field);
else if (is(Type == struct)) {
interpolate(
__traits(getMember, result, field), idx,
__traits(getMember, data1, field),
__traits(getMember, data2, field));
} else if (is(Type == U[n], U, size_t n)) {
foreach (i; 0 .. n) {
interpolate(
__traits(getMember, result, field)[i], idx,
__traits(getMember, data1, field)[i],
__traits(getMember, data2, field)[i]);
}
}
}
}
This looks a lot like serialization. What you have done looks more specific to your use case though. Why not call a function recursively for each type encountered?
e.g.:
auto interpolate(alias fn, X : double)(ref X val1, ref X val2)
{
static if(is(typeof(fn(val1, val2)))) return fn(val1, val2);
}
auto interpolate(alias fn, X)(ref X val1, ref X val2) if (is(X == struct))
{
// loop and recurse
}
...
Then you can write a set of templates that act on the right types, and do the thing you want for that specific type, pass that in as fn
.
I find splitting the work into distinct portions when doing these kinds of introspection tasks to be more straightforward and testable.
-Steve