[static] foreach scope, template declaration ?

Ali Çehreli via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Thu Sep 25 16:37:10 PDT 2014


On 09/25/2014 04:08 PM, SlomoTheBrave wrote:

 > On Thursday, 25 September 2014 at 22:11:20 UTC, Mathias LANG wrote:
 >> I'm a bit puzzled with the following behavior:
 >>
 >> ----
 >> import std.typetuple, std.traits;
 >>
 >> struct UDAStruct {
 >>     string identifier;
 >> }
 >>
 >> class MyClass {
 >>     @(UDAStruct("p1"), UDAStruct("p2"), UDAStruct("P3")) // P3 is a typo
 >>       void func(int p1, string p2, float p3) {}
 >> }
 >>
 >> unittest {
 >>     alias Func = MyClass.func;
 >>     enum ParamNames = ParameterIdentifierTuple!Func;
 >>     enum ParamAttr = __traits(getAttributes, Func);
 >>
 >>     foreach (attr; ParamAttr) {
 >>         template CmpName(string PName) {
 >>             pragma(msg, "Instantiated for: "~PName);
 >>             enum CmpName = (PName == attr.identifier);
 >>         }
 >>         pragma(msg, "Current attr is: "~attr.identifier);
 >>         static assert(anySatisfy!(CmpName, ParamNames));

The first invocation of that line will instantiate CmpName with 
ParamNames, which happens to be a TypeTuple of "p1", "p2", and "p3".

 > the output lines order shows there is a problem too:
 >
 >> Current attr is: p1
 >> Instantiated for: p1
 >> Instantiated for: p2
 >> Instantiated for: p3

Surprisingly, that indicates that anySatisfy did instantiate CmpName 
with all three string values, meaning that perhaps we don't have 
shortcut behavior for 'bool' eponymous templates.

Copying and instrumenting anySatisfy's implementation:

template myAnySatisfy(alias F, T...)
{
     pragma(msg, "myAnySatisfy with "~[ T ]);
     static if(T.length == 0)
     {
         enum myAnySatisfy = false;
         pragma(msg, "length == 0 "~myAnySatisfy);
     }
     else static if (T.length == 1)
     {
         enum myAnySatisfy = F!(T[0]);
         pragma(msg, "length == 1 "~myAnySatisfy);
     }
     else
     {
         enum myAnySatisfy =
             myAnySatisfy!(F, T[ 0  .. $/2]) ||
             myAnySatisfy!(F, T[$/2 ..  $ ]);
         pragma(msg, "else "~myAnySatisfy);
     }
}

When I use myAnySatisfy instead of anySatisfy, I see that I am right: 
The last expression above does not stop instantiating after "p1". In 
other words, even though myAnySatisfy!(F, T[$/2 ..  $ ] is unnecessary 
(because the first part of || is already 'true'), it gets instantiated 
anyway.

Current attr is: p1
["myAnySatisfy with ", "p1", "p2", "p3"]
["myAnySatisfy with ", "p1"]
Instantiated for: p1
length == 1 
["myAnySatisfy with ", "p2", "p3"]
["myAnySatisfy with ", "p2"]
Instantiated for: p2
length == 1
["myAnySatisfy with ", "p3"]
Instantiated for: p3
length == 1
else
else 
Current attr is: p2
Current attr is: P3

This looks like an enhancement request.

Ali



More information about the Digitalmars-d-learn mailing list