www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - MemberDefaults trait

reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
Could you please review the following template to see whether it makes 
sense. It produces an AliasSeq type consisting of the default values of 
the members of a struct. It should and does support members that are 
initialized with '= void'. I could not achieve this with std.traits or 
__traits.

However, I'm not that happy with the use of __traits(compiles) below. 
Can this be improved?

Thank you,
Ali


import std.meta;

/** Get as an expression tuple the default values of members of a struct. */
template MemberDefaults(T) {
     static if (!is(T == struct)) {
         static assert(T.stringof ~ " is not a struct type");
     }

     import std.traits : FieldNameTuple;
     enum t = T.init;
     alias fields = FieldNameTuple!T;

     template get(size_t i) {
         static if (__traits(compiles, { enum _ = t.tupleof[i]; })) {
             enum get = t.tupleof[i];
         }
         else {
             alias get = void;
         }
     }

     template Impl(size_t i = 0) {
         import std.meta : AliasSeq;
         static if (i == fields.length) {
             alias Impl = AliasSeq!();
         } else {
             alias Impl = AliasSeq!(get!i, Impl!(i+1));
         }
     }

     alias MemberDefaults = Impl!();
}

unittest {
     struct S {
         int i = 42;
         string s = "hello";
         char c = 'c';
     }

     static assert(MemberDefaults!S == AliasSeq!(42, "hello", 'c'));
}

unittest {
     struct S {
         int i = 42;
         int j = void;
     }

     static assert(MemberDefaults!S[0] == 42);
     static assert(is(MemberDefaults!S[1] == void));
}

void main() {
}
Oct 10 2016
next sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 10/10/2016 04:50 PM, Ali Çehreli wrote:

     static if (!is(T == struct)) {
         static assert(T.stringof ~ " is not a struct type");
     }
Wow! That's a nice brain fart on my part. Ok, I can fix that one... :) Ali
Oct 10 2016
prev sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 10/10/2016 04:50 PM, Ali Çehreli wrote:
 Could you please review the following template to see whether it makes
 sense. It produces an AliasSeq type consisting of the default values of
 the members of a struct. It should and does support members that are
 initialized with '= void'. I could not achieve this with std.traits or
 __traits.
Reviving this thread because I've realized that the template does not work for members that are structs themselves. /** Get as an expression tuple the default values of members of a struct. */ template MemberDefaults(T) { static assert (is(T == struct), T.stringof ~ " is not a struct type"); import std.traits : FieldNameTuple; enum t = T.init; alias fields = FieldNameTuple!T; template get(size_t i) { static if (__traits(compiles, { enum get = t.tupleof[i]; })) { enum get = t.tupleof[i]; } else { alias get = void; } } template Impl(size_t i = 0) { import std.meta : AliasSeq; static if (i == fields.length) { alias Impl = AliasSeq!(); } else { alias Impl = AliasSeq!(get!i, Impl!(i+1)); } } alias MemberDefaults = Impl!(); } struct Foo { string s; int i; } unittest { struct S { int i = 42; string s = "hello"; char c = 'c'; int j = void; Foo foo0; Foo fooVoid = void; } alias result = MemberDefaults!S; import std.meta : AliasSeq; if (!is(result == AliasSeq!(42, "hello", 'c', void, Foo, void))) { pragma(msg, "Did not match: ", result); static assert(false); } } void main() { } Here is the output of a -unittest compilation: Did not match: tuple(42, "hello", 'c', (void), Foo(null, 0), Foo(, )) Notice how the j member worked as expected: Its default value appeared as (void) in the result. (Aside: It's strange that pragma(msg) parenthesizes it.) The problem is, the default value of the fooVoid member does not appear as void but as "Foo(, )". This seems to be a compiler bug to me. One might parse that string as a workaround but then it wouldn't work for empty structs. (Although, empty structs could be excluded by this template. Hmmm... That might work.) Can you make this work? i.e. Can you make the result be AliasSeq!(42, "hello", 'c', void, Foo, void) Is it possible to detect members that are void-initialized at all? Ali
Mar 14 2017