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

// Foreach does introduce a scope, as this produce no compile time error.
    template CmpName(string test) { enum CmpName = test; }
    static assert(CmpName!"?" == "?");
}

void main() {}
----

The output is (FE 2.066 & 2.065 tested):
148 geod24@barsoom2 ~ % dmd -unittest -run test.d
Current attr is: p1
Instantiated for: p1
Instantiated for: p2
Instantiated for: p3
Current attr is: p2
Current attr is: P3

Obviously one call tell it's not what I expected. It looks like DMD is reusing the instantiations of the template of the first loop for p2 and P3. The 2 lines at the end check that foreach does introduce a scope, but it behaves differently than what we're use to.

Is there a way around this ?
I tried to move CmpName outside the loop, then declare `alias Cmp(string x) = CmpName(attr, x);` in the loop, but it doesn't help (I guess the same thing happens?).

a way around this is not to use anySatisfy nor the template, for example this works as expected:

import std.typetuple, std.traits;

struct UDAStruct {
    string identifier;
}

class MyClass {
@(UDAStruct("p1"), UDAStruct("p2"), UDAStruct("P3")) // P3 isa typo
      void func(int p1, string p2, float p3) {}
}

------
void main(string[] args){

    alias Func = MyClass.func;
    enum ParamNames = ParameterIdentifierTuple!Func;
    enum ParamAttr = __traits(getAttributes, Func);

    foreach(i,attr; ParamAttr) {
static assert(attr.identifier == ParamNames[i], attr.identifier);
    }
}
------

which is less abstruse. However I don't know if it has hurted your eyes too but the output lines order shows there is a problem too:

Current attr is: p1
Instantiated for: p1
Instantiated for: p2
Instantiated for: p3
Current attr is: p2
Current attr is: P3

instead of

Current attr is: p1
Instantiated for: p1
Current attr is: p2
Instantiated for: p2
Current attr is: P3
Instantiated for: p3

o!o

Reply via email to