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]);
}