Generic structural recursion
Steven Schveighoffer
schveiguy at gmail.com
Wed Jan 26 19:06:18 UTC 2022
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.:
```d
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
More information about the Digitalmars-d
mailing list