A template returning a delegate [was: template returning delegate]

Marek Janukowicz marek at janukowicz.net
Wed Aug 21 17:45:37 PDT 2013


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


More information about the Digitalmars-d-learn mailing list