What's wrong with this template function?

Ali Çehreli acehreli at yahoo.com
Thu Jan 3 19:38:39 UTC 2019


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



More information about the Digitalmars-d-learn mailing list