Thread overview
Build an AliasSeq from memberFunction return types
Mar 09, 2018
Timoses
Mar 09, 2018
Simen Kjærås
Mar 19, 2018
Timoses
March 09, 2018
Hi,

I feel like starting to dig deeper into D. And I got lost : D.

I would like to reflect on defined bitfields:

   struct S
   {
      mixin!(bitfields!(
         <bitfieldType>, <bitfieldName>, <size>,
         ...
      ));
   }

which produces something like this in the back scenes:

   struct S
   {
      uint storage;

      @property <bitfieldType> <bitfieldName>() {
         ... return field from storage;
      }
   }

There is an approach here:
https://forum.dlang.org/post/o5u21b$15f3$1@digitalmars.com
However, it feels a bit overcomplicating the issue perhaps.

To retrieve the member names the following (and filtering for only the functions) does the job:

   alias members = aliasSeqOf!([__traits(allMembers, S)]);

However, I now would want to build an AliasSeq of the types. My idea would be (absolute pseudocode!!!):

   alias memberTypes;
   static foreach (member; members)
   {
      memberTypes ~= ReturnType!S.member;
   }

   pragma(msg, memberTypes); // prints sth like: (int, bool, uint, ...)

I have taken a look at https://dlang.org/phobos/std_meta.html but am unsure whether I can actually build an AliasSeq iteratively.

The mentioned example might help:
   alias TL = AliasSeq!(int, double);
   alias Types = AliasSeq!(TL, char);
   static assert(is(Types == AliasSeq!(int, double, char)));

However, I can't simply do

   static foreach (i, member; members)
   {
      alias memberTypes_i = AliasSeq!
         (memberTypes_i, ReturnType!S.<member>) // <--- no idea even how to get
                                                // the ReturnType here...
                                                // S.member does not work
   }
   alias memberTypes = AliasSeq!(memberTypes_i_max);

But what the heck! I can't find a solution!
This might be related to:
https://forum.dlang.org/post/pxtqeahzxrsrljnrworq@forum.dlang.org

Do you have any ideas? Or does your head start spinning like mine does, too?
March 09, 2018
On Friday, 9 March 2018 at 17:47:46 UTC, Timoses wrote:
> To retrieve the member names the following (and filtering for only the functions) does the job:
>
>    alias members = aliasSeqOf!([__traits(allMembers, S)]);

This can be simplified to
alias members = Alias!(__traits(allMembers, S));


> However, I now would want to build an AliasSeq of the types. My idea would be (absolute pseudocode!!!):
>
>    alias memberTypes;
>    static foreach (member; members)
>    {
>       memberTypes ~= ReturnType!S.member;
>    }

Generally, we use recursive templates in these cases:

template GetMemberTypes(funcs...) {
    static if (funcs.length == 0) {
        alias GetMemberTypes = AliasSeq!();
    } else {
        alias GetMemberTypes = AliasSeq!(
              ReturnType!(funcs[0]),
              GetMemberTypes!(funcs[1..$])
              );
    }
}


However, std.meta has staticMap, which will do this recursion for us:

alias memberTypes = staticMap!(ReturnType, members);

Of course, this assumes 'members' contains only the functions you care about. All in all, what you want can be boiled down to this code:


import std.meta : staticMap, Alias, Filter;
import std.traits : isFunction, ReturnType;
import std.bitmanip : bitfields;

struct A
{
    int a;
    mixin(bitfields!(
        uint, "x",    2,
        int,  "y",    3,
        uint, "z",    2,
        bool, "flag", 1));
}

template GetMember(T) {
    alias GetMember(string name) = Alias!(__traits(getMember, T, name));
}
alias memberTypes = staticMap!(ReturnType, Filter!(isFunction, staticMap!(GetMember!A, __traits(allMembers, A))));


So, how does it work?

GetMember is a template that takes an aggregate type as a parameter and returns a new template that takes a string. This inner template then returns the member of the aggregate type that has that name:

// Define a template that will find a member in A.
alias GetMemberOfA = GetMember!A;

// Get the 'flag' member of A.
alias someMemberOfA = GetMemberOfA!"flag";



Next: This line is a bit of a mouthful, so let's break it down:
alias memberTypes = staticMap!(ReturnType, Filter!(isFunction, staticMap!(GetMember!A, __traits(allMembers, A))));

becomes:

// Grab the name of every single member of A.
alias allMemberNames = Alias!(__traits(allMembers, A));

// Define a template that will find a member in A.
alias GetMemberOfA = GetMember!A;

// Now get the members of A that correspond to the names __traits(allMembers) returned.
alias allMembers = staticMap!(GetMemberOfA, allMemberNames);

// Get rid of everything that's not a function.
alias onlyFunctions = Filter!(isFunction, allMembers);

// And finally grab the return type of each function.
alias memberTypes = staticMap!(ReturnType, onlyFunctions);

--
  Simen
March 19, 2018
I couldn't have wished for a better answer!

Thank you so much, Simen.