What's wrong with this template function?

Machine Code jckj33 at gmail.com
Thu Jan 3 20:34:17 UTC 2019


On Thursday, 3 January 2019 at 19:38:39 UTC, Ali Çehreli wrote:
> 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


Thank you very much, Ali. So the issue was basically I can't 
return from a static foreach() loop right? I think I've read that 
but totally forgot. I just used -1 instead of size_t.max and 
turned into array the result from __traits(derivedMembers, T) so 
that I index it later on, in case of the function return.


I did small changes, end up with this:

T first(T)()
{
	enum fields = [__traits(derivedMembers, T)];
	auto first_()
	{
		auto result = -1;
		static foreach(i, field; fields)
		{
			static if(is(typeof(__traits(getMember, T, field)) == T))
			{
				if(result == -1)
				{
					result = i;
				}
			}
		}
		return result;
	}

	enum found = first_();
	import std.string : format;
	static assert(found != -1,
			format!"no first member of type %s found"(T.stringof));
	return __traits(getMember, T, fields[found]);
}



More information about the Digitalmars-d-learn mailing list