www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - template returning delegate

reply Marek Janukowicz <marek janukowicz.net> writes:
Yet another problem I just spotted:

-----------------------

import std.stdio, std.string;

struct Val {
  int i;
  byte b;
} 

template templ( T ) {

   auto templ (T obj, string name) {
    foreach( s; __traits(derivedMembers, T)) {
      if (s == name) {
        static if( is(typeof(__traits(getAttributes, __traits(getMember, T, 
s))) blah)) { // Rule out "non-regular" members
          //return format( "%s", __traits(getMember, obj, s)); // Version A
          return cast(string delegate())() { return 
format("%s",__traits(getMember, obj, s)); }; // Version B
        }
      }
    }
    throw new Exception("Invalid member");
  }
}

void main (string [] args) {
  Val v = Val(1, 2);
  //writefln( "%s: %s", args[1], templ!()(v, args[1]));   // Version A
  writefln( "%s: %s", args[1], templ!()(v, args[1])()); // Version B
}

---------------------------

Now running:
$ dmd -run member.d i
/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.3/../../../../x86_64-pc-linux-
gnu/bin/ld: Warning: size of symbol 
`_D6member23__T5templTS6member3ValZ5templFNfS6member3ValAyaZDFZ
ya9__lambda1MFZAya' 
changed from 32 in member.o to 33 in member.o
i: 1

$ dmd -run member.d b
/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.3/../../../../x86_64-pc-linux-
gnu/bin/ld: Warning: size of symbol 
`_D6member23__T5templTS6member3ValZ5templFNfS6member3ValAyaZDFZ
ya9__lambda1MFZAya' 
changed from 32 in member.o to 33 in member.o
b: 1  # Why not 2?

If I compile using ldc2 I get exactly the same result, so the delegate 
returned from template always returns value of "i" member (maybe it's always 
the first member that is returned). Ld warning is not present then.

However if I comment "Version B" lines and uncomment "Version A" (which 
means I return the result directly instead of returning the delegate I get 
expected results:

$ dmd -run member.d i
i: 1

$ dmd -run member.d b
b: 2

Also no ld warning in this case.

-- 
Marek Janukowicz
Aug 21 2013
next sibling parent Marek Janukowicz <marek janukowicz.net> writes:
After I sent the message I realized my limited English knowledge made me 
make a subject that actually had quite a different meaning than I intended 
:)

Now it's hopefully fine or at least less ambiguous.

-- 
Marek Janukowicz
Aug 21 2013
prev sibling parent Marek Janukowicz <marek janukowicz.net> writes:
Marek Janukowicz wrote:

 Yet another problem I just spotted:
 
 -----------------------
 
 import std.stdio, std.string;
 
 struct Val {
   int i;
   byte b;
 }
 
 template templ( T ) {
 
    auto templ (T obj, string name) {
     foreach( s; __traits(derivedMembers, T)) {
       if (s == name) {
         static if( is(typeof(__traits(getAttributes, __traits(getMember,
         T,
 s))) blah)) { // Rule out "non-regular" members
           //return format( "%s", __traits(getMember, obj, s)); // Version
           A return cast(string delegate())() { return
 format("%s",__traits(getMember, obj, s)); }; // Version B
         }
       }
     }
     throw new Exception("Invalid member");
   }
 }
 
 void main (string [] args) {
   Val v = Val(1, 2);
   //writefln( "%s: %s", args[1], templ!()(v, args[1]));   // Version A
   writefln( "%s: %s", args[1], templ!()(v, args[1])()); // Version B
 }
 
 ---------------------------
 
 Now running:
 $ dmd -run member.d i
 /usr/lib/gcc/x86_64-pc-linux-gnu/4.6.3/../../../../x86_64-pc-linux-
 gnu/bin/ld: Warning: size of symbol
 
`_D6member23__T5templTS6member3ValZ5templFNfS6member3ValAyaZDFZAya9__lambda1MFZAya'
 changed from 32 in member.o to 33 in member.o
 i: 1
 
 $ dmd -run member.d b
 /usr/lib/gcc/x86_64-pc-linux-gnu/4.6.3/../../../../x86_64-pc-linux-
 gnu/bin/ld: Warning: size of symbol
 
`_D6member23__T5templTS6member3ValZ5templFNfS6member3ValAyaZDFZAya9__lambda1MFZAya'
 changed from 32 in member.o to 33 in member.o
 b: 1  # Why not 2?
 
 If I compile using ldc2 I get exactly the same result, so the delegate
 returned from template always returns value of "i" member (maybe it's
 always the first member that is returned). Ld warning is not present then.
 
 However if I comment "Version B" lines and uncomment "Version A" (which
 means I return the result directly instead of returning the delegate I get
 expected results:
 
 $ dmd -run member.d i
 i: 1
 
 $ dmd -run member.d b
 b: 2
 
 Also no ld warning in this case.
Figured it out - this code works as expected: import std.stdio, std.string; struct Val { int i; byte b; } template templ( T ) { auto dg(alias s)( T obj ) { return () { return format("%s",__traits(getMember, obj, s)); }; } auto templ (T obj, string name) { foreach( s; __traits(derivedMembers, T)) { if (s == name) { static if( is(typeof(__traits(getAttributes, __traits(getMember, T, s))) blah)) { // Rule out "non-regular" members return dg!(s)(obj); } } } throw new Exception("Invalid member"); } } void main (string [] args) { Val v = Val(1, 2); writefln( "%s: %s", args[1], templ!()(v, args[1])()); } My mistake was to return delegate with __traits directly inside, why the correct way to do this was to create delegate using template. However, now I'm a bit confused my code worked at all instead of failing right away. -- Marek Janukowicz
Aug 21 2013