digitalmars.D.learn - What's wrong with this template function?
- Machine Code (38/38) Jan 03 2019 I wrote a small routine to return the first member of type T of a
- =?UTF-8?Q?Ali_=c3=87ehreli?= (58/95) Jan 03 2019 I see that that's possible because the values of such members are known
- Machine Code (31/140) Jan 03 2019 Thank you very much, Ali. So the issue was basically I can't
- Neia Neutuladh (14/16) Jan 03 2019 The static foreach is done at compile time and the return is done at
- Machine Code (2/18) Jan 03 2019 Thank you for the clarification :)
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)); }
Jan 03 2019
On 01/03/2019 10:49 AM, Machine Code wrote:I wrote a small routine to return the first memberI 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
Jan 03 2019
On Thursday, 3 January 2019 at 19:38:39 UTC, Ali Çehreli wrote:On 01/03/2019 10:49 AM, Machine Code wrote: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]); }I wrote a small routine to return the first memberI 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 somethingelse thanreturn 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 %sfound"(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
Jan 03 2019
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.
Jan 03 2019
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 for the clarification :)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.
Jan 03 2019