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