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