Store struct tuple of alias and access members through it?

Simen Kjærås simen.kjaras at gmail.com
Sat Apr 7 19:21:30 UTC 2018


On Saturday, 7 April 2018 at 13:31:01 UTC, Timoses wrote:
> In the end I would like to accomplish the following:
> Provide access to contained bitfields and members of a struct 
> in the order they
> appear in the struct via an index.

The behavior of Type.tupleof in D seems a bit unfinished - they 
can't be passed to other functions, they can't be directly used 
to get the member they refer to, and the indirect way is clunky.

Anyways. Your desired code `return this.m.members[i];` is, as you 
have noticed, impossible. There's multiple reasons for that - 
first, `members` can't be used like that. Second, since you need 
to wrap it in a Param instance, you need more information than 
that. Third, there's a clear distinction in D between 
compile-time and run-time values, so you need the static foreach 
there to get the right compile-time value.

Now, what *can* we do?

First, there's no need for __traits(getMember, this.m, 
members[j].stringof), since the index into T.tupleof is the exact 
same as for m.tupleof. In other words, you could use

     return new Param!(typeof(m.tupleof[j]))(m.tupleof[j]);

I think that is clearer. I'd suggest also creating this function:

     IParam param(T)(T value) {
         return new Param!T(value);
     }

That way, the above line would be

     return param(m.tupleof[j]);

Handling methods is a tad more complicated, and you will not get 
the correct interleaving of methods and fields, which may or may 
not be a problem to you.

Here's my attempt at solving all your problems. There may be 
things I've misunderstood, forgotten or ignored, and there are 
certainly places where I'm unsure.


import std.meta;
import std.traits;

// List all member functions, and wrap them such that 
myFoo.fun(3) can be called as 
AllMemberFunctions!(typeof(myFoo))[idx](myFoo, 3).
template AllMemberFunctions(T)
{
     template createDg(alias fn)
     {
         static if (__traits(isStaticFunction, fn))
             alias createDg = fn;
         else
             ReturnType!fn createDg(ref T ctx, Parameters!fn args)
             {
                 ReturnType!fn delegate(Parameters!fn) fun;
                 fun.funcptr = &fn;
                 fun.ptr = cast(void*)&ctx;
                 return fun(args);
             }
     }

     alias GetOverloads(string name) = 
AliasSeq!(__traits(getOverloads, T, name));

     alias AllMemberFunctions = staticMap!(createDg, 
staticMap!(GetOverloads, __traits(allMembers, T)));
}

interface IParam
{
     // Moved this here, since otherwise you'd need to know the
     // exact template parameters to Param to get to anything.
     IParam opIndex(size_t i);
}


// Simplified template definition.
class Param(T) : IParam
{
     T m;
     this(T m)
     {
         this.m = m;
     }

     static if (!isBasicType!T && !isArray!T && 
!isFunctionPointer!T)
     {
         IParam opIndex(size_t i)
         {
             switch (i)
             {
                 // Go through all members:
                 static foreach (j; 0..m.tupleof.length)
                     case j:
                         return param(m.tupleof[j]);
                 // Then all functions after:
                 static foreach (j, fn; AllMemberFunctions!T)
                     case j+m.tupleof.length:
                         return param(&fn);
                 // And blow up if the index is invalid.
                 default:
                     assert(false, "Invalid index!");
             }
         }
     }
     else
     {
         IParam opIndex(size_t i)
         {
             assert(false, T.stringof ~ " is not an aggregate 
type, and can't be indexed.");
         }
     }
}

IParam param(T)(T value) {
     return new Param!T(value);
}

struct S {
     int n;
     float f;
     string s;
     int fn() { return n+2; }
     string fun() { return ""; }
     string fun(int n) { return ""; }
     static void func() {}
}


unittest {
     S s;
     IParam a = param(s);
}

--
   Simen


More information about the Digitalmars-d-learn mailing list