digitalmars.D.learn - Store struct tuple of alias and access members through it?
- Timoses (82/82) Apr 07 2018 (Please read at the very bottom what I'd like to achieve)
- Simen =?UTF-8?B?S2rDpnLDpXM=?= (115/119) Apr 07 2018 The behavior of Type.tupleof in D seems a bit unfinished - they
- Timoses (10/38) Apr 19 2018 Many thanks for this!!! Was really helpful.
- Alex (74/74) Apr 07 2018 On Saturday, 7 April 2018 at 13:31:01 UTC, Timoses wrote:
(Please read at the very bottom what I'd like to achieve)
Is it possible to return the member of a struct by its .tupleof
index?
I know that it would work on a struct value, but I'd like it to
work on the type's tupleof:
```
struct S { int i;}
S s;
// below leads to: Error: need this for s1 of type uint
// writeln(/*somehow access s via the S tupleof? */ S.tupleof[0]);
// vs
writeln(s.tupleof[0]);
```
See below example to make the intention a bit clearer:
https://run.dlang.io/gist/6fdb01ddd78b14f8b9a94ac951580cb8
```
struct S
{
uint s1;
ushort s2;
}
interface IParam
{}
template Param(T)
{
static if (isBasicType!T)
alias members = AliasSeq!();
else
alias members = AliasSeq!(T.tupleof);
class Param : IParam
{
T m;
this(T m)
{
this.m = m;
}
IParam opIndex(size_t i)
{
// Something like this possible?????
// return this.m.members[i]; // <------------
how???
// This works but feels needless.
static foreach (j, t; members)
if (i == j)
{
return new
Param!(typeof(members[j]))(__traits(getMember, this.m,
members[j].stringof)); // <-------------
members[j].stringof feels ugly just to get the member that should
be stored in 'members' already...
}
return null;
}
}
}
```
The reason why I don't want `m.tupleof[i]` is because later I'd
like to consider bitfields within the struct. This means I'd have
to also consider the member functions of the struct and
potentially return them.
E.g.
```
struct S
{
int s1;
int s2() { return 3; }
}
```
and then I'd like to have
alias members = (s1, s2) // pseudo code..
so I could return
S s;
s.members[1]; // would evaluate the function s2 and return the
value
----------
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.
I hope I made a somewhat decent job in explaining what I'm trying
to accomplish.
Please let me know if anything is unclear.
Apr 07 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
Apr 07 2018
On Saturday, 7 April 2018 at 19:21:30 UTC, Simen Kjærås wrote:
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)));
}
--
Simen
Many thanks for this!!! Was really helpful.
I ended up unfolding the struct members into an array of member
strings and mapping those to either the struct tuple members or
the struct function members.
This way I can call all members (normal and bitfield members) in
order.
Result:
https://gist.github.com/Timoses/c78e599e91b8d05be34aefaf75ca3739
This project is really teaching me some template actions : D.
Apr 19 2018
On Saturday, 7 April 2018 at 13:31:01 UTC, Timoses wrote:
Simen was faster :)
In my solution I simply ignore such things as functions... But
there is the cool delegate creation approach in Simen's solution
for this. I can handle arrays instead. :)
And I got rid of tupelof acting on an instance.
Be aware, that bitfields create more fields then the delegates
for the bitfield's members...
import std.stdio;
import std.bitmanip;
import std.traits;
void main()
{
S s;
Param!S example = new Param!S(s);
writeln(example[0]);
writeln(example[1]);
writeln(example[2]);
writeln(example[3]);
writeln(example[4]);
writeln(example[5]);
writeln(example[6]);
writeln([__traits(allMembers, S)]);
writeln(example[15]);
writeln(example[16]);
writeln(example[17]);
writeln(example[18]);
}
struct S
{
uint s1;
ushort s2;
string s3;
float s4;
mixin(bitfields!(
uint, "x", 2,
int, "y", 3,
uint, "z", 2,
bool, "flag", 1));
size_t fun(){ return 42; }
size_t delegate() dg;
size_t[] arr;
static void fun(){}
}
interface IParam{}
class Param(T) : IParam
{
T m;
this(T m)
{
this.m = m;
}
IParam opIndex(size_t i)
{
//static if(!isBasicType!T)
static if(__traits(compiles, __traits(allMembers, T)))
{
static foreach (j, t; __traits(allMembers, T))
{
if (i == j)
{
static if(__traits(compiles, new
Param!(typeof(__traits(getMember, this.m,
t)))(__traits(getMember, this.m, t))))
{
return new Param!(typeof(__traits(getMember,
this.m, t)))(__traits(getMember, this.m, t));
}
}
}
}
return null;
}
}
Apr 07 2018









Timoses <timosesu gmail.com> 