On Saturday, 13 June 2015 at 10:01:45 UTC, JDemler wrote:
Hey,
i am trying to wrap my head around __traits.
One thing i just do not understand is following:
struct S{
string member1;
int member2;
}
void main(string[] args)
{
foreach(typeStr; __traits(allMembers, S))
{
auto tp = __traits(getMember, S, typeStr);
static if (__traits(isArithmetic, tp))
writeln(typeStr ~ " is Arithmetic");
}
}
Does not compile. "main.d(15): Error: need 'this' for 'member1'
of type 'string'"
But if the inner part of the foreach-loop is changed to:
static if (__traits(isArithmetic, __traits(getMember, S,
typeStr)))
writeln(typeStr ~ " is Arithmetic");
it compiles and does exactly what i expect it to do.
If i understand it correctly __traits(getMember returns a
reference to that member, so i get why i shouldn't be able to
use
it with the class instead of an instance of a class.
But why does it work if it is nested inside a __traits call?
"auto tp" is treating a runtime variable, but you don't have an
actual instance of S. What you want is an alias of the symbol
without creating an instance.
Unfortunately alias tp = __traits(getMember, S, typeStr); doesn't
work, but if you steal* Alias from std.typetuple(or std.meta, if
you're running a very recent dmd build) then you can do
alias tp = Alias!(__traits(getMember, S, typeStr));
and then it will work for you.
*for some reason it's not public, but it's very short and simple:
template Alias(alias a)
{
static if (__traits(compiles, { alias x = a; }))
alias Alias = a;
else static if (__traits(compiles, { enum x = a; }))
enum Alias = a;
else
static assert(0, "Cannot alias " ~ a.stringof);
}
// types and tuples
template Alias(a...)
{
alias Alias = a;
}
unittest
{
enum abc = 1;
static assert(__traits(compiles, { alias a = Alias!(123); }));
static assert(__traits(compiles, { alias a = Alias!(abc); }));
static assert(__traits(compiles, { alias a = Alias!(int); }));
static assert(__traits(compiles, { alias a =
Alias!(1,abc,int); }));
}