On 01/03/2019 10:49 AM, Machine Code wrote:

> I wrote a small routine to return the first member

I see that that's possible because the values of such members are known at compile time in your case. Otherwise, you would need a mechanism that would return the value of the first member for any object at runtime.

> of type T of a same
> type, like struct below, but the assert is reached albeit the "yes"
> message is printed. What am I missing? should I use something else than
> return keyword to return from a template function or what?
>
> struct Color
> {
>      enum red = Color("red", 30);
>      enum blue = Color("blue", 40);
>      enum green = Color("green");
>
>      string name;
>      int value;
>      alias value this;
> }
>
> the routine:
>
> T first(T)()
> {
>      import std.string : format;
>      pragma(msg, format!"types = %s"([__traits(derivedMembers, T)]));
>
>      static foreach(field; [__traits(derivedMembers, T)])
>      {
>          // exit on first match
>          pragma(msg, format!"member %s"(field));
>          static if(is(typeof(__traits(getMember, T, field)) == T))
>          {
>              pragma(msg, "yes");
>              return __traits(getMember, T, field);
>          }
>          else
>          {
>              pragma(msg, "no");
>          }
>      }
>      import std.string : format;
>      static assert(0,
>          format!"no first member of type %s found"(T.stringof));

That will always be checked at compile time and will always fail because that line is not excluded from the compilation by another compile-time check. It is a part of the function body and the compiler will have to compile it and fail that check.

> }

You're basically performing a search at compile time and want to fail if something is not found. I came up with the following method where a nested function is used to return an index. The outer code calls the function to set a compile-time expression (found) and is able to check that something is found. (There are too many size_t.max's in the code; cleanup needed. :) )

struct Color
{
    enum red = Color("red", 30);
    enum blue = Color("blue", 40);
    enum green = Color("green");

    string name;
    int value;
    alias value this;
}

T first(T)()
{
    import std.string : format;
    pragma(msg, format!"types = %s"([__traits(derivedMembers, T)]));

    alias fields = __traits(derivedMembers, T);

    auto first_() {
      auto result = size_t.max;
      static foreach(i, field; fields)
      {
        // exit on first match
        pragma(msg, format!"member %s"(field));
        static if(is(typeof(__traits(getMember, T, field)) == T))
        {
          pragma(msg,"yes");
          if (result == size_t.max) {
            result = i;
          }
        }
        else
        {
          pragma(msg, "no");
        }
      }
      return result;
    }

    enum found = first_();

    import std.string : format;
    static assert(found != size_t.max,
                  format!"no first member of type %s found"(T.stringof));

    return __traits(getMember, T, fields[found]);
}

void main() {
  pragma(msg, first!Color);
}

Ali

Reply via email to