Thread overview | |||||||
---|---|---|---|---|---|---|---|
|
January 03, 2019 What's wrong with this template function? | ||||
---|---|---|---|---|
| ||||
I wrote a small routine to return the first member 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)); } |
January 03, 2019 Re: What's wrong with this template function? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Machine Code | 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 |
January 03, 2019 Re: What's wrong with this template function? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | 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]); } |
January 03, 2019 Re: What's wrong with this template function? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Machine Code | On Thu, 03 Jan 2019 20:34:17 +0000, Machine Code wrote:
> Thank you very much, Ali. So the issue was basically I can't return from a static foreach() loop right?
The static foreach is done at compile time and the return is done at runtime.
After the template is expanded, your code ends up looking like:
Color first()
{
return Color.red;
return Color.blue;
return Color.green;
static assert(false);
}
And that doesn't compile, because there's a static assert there that fails. It's not at any line of code that would execute at runtime, but the compiler doesn't care about that.
|
January 04, 2019 Re: What's wrong with this template function? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Neia Neutuladh | On Thursday, 3 January 2019 at 21:41:44 UTC, Neia Neutuladh wrote:
> On Thu, 03 Jan 2019 20:34:17 +0000, Machine Code wrote:
>> Thank you very much, Ali. So the issue was basically I can't return from a static foreach() loop right?
>
> The static foreach is done at compile time and the return is done at runtime.
>
> After the template is expanded, your code ends up looking like:
>
> Color first()
> {
> return Color.red;
> return Color.blue;
> return Color.green;
> static assert(false);
> }
>
> And that doesn't compile, because there's a static assert there that fails. It's not at any line of code that would execute at runtime, but the compiler doesn't care about that.
Thank you for the clarification :)
|
Copyright © 1999-2021 by the D Language Foundation