Re: Store struct tuple of alias and access members through it?
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.
Re: Store struct tuple of alias and access members through it?
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; } }
Re: Store struct tuple of alias and access members through it?
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
Store struct tuple of alias and access members through it?
(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.