digitalmars.D.learn - Traits and UDAs
- Chris Williams (46/46) Jun 06 2013 I decided to write up a little application to test using User
- Adam D. Ruppe (52/52) Jun 06 2013 Here's how I do it:
- Dicebot (4/5) Jun 06 2013 It will work if use "enum" instead of "auto" for storing
I decided to write up a little application to test using User Defined Attributes and have one question. Here is a working application that allows me to mark certain members of a function to be dumped: import std.stdio; enum Dump = "Dump"; template Dumper(T) { void dump() { foreach (mem; __traits(allMembers, T)) { auto attributes = __traits(getAttributes, __traits(getMember, T, mem)); static if ( attributes.length > 0 && __traits(getAttributes, __traits(getMember, T, mem))[0] == Dump ) { writeln(mem); } } } } class Foo { Dump int hello; Dump int world; int bye; mixin Dumper!(Foo); } int main(string[] args) { Foo f = new Foo(); f.dump(); return 0; } The eighth line bothers me, though. It seems like I should be able to write: if (attributes.length > 0 && attributes[0] == Dump) However, that fails to compile with the message: test.d(7): Error: variable _attributes_field_0 cannot be read at compile time test.d(8): Error: expression !!(_attributes_field_0 == "Dump") is not constant or does not evaluate to a bool test.d(7): Error: variable _attributes_field_0 cannot be read at compile time test.d(8): Error: expression !!(_attributes_field_0 == "Dump") is not constant or does not evaluate to a bool Any thoughts?
Jun 06 2013
Here's how I do it: enum Dump; // just a type, no value here template Dumper(T) { void dump() { foreach (mem; __traits(allMembers, T)) { // loop over the attrs instead of try to store them in a var foreach(attr; __traits(getAttributes, __traits(getMember, T, mem))) // identify them by type rather than value static if ( is(attr == Dump)) { writeln(mem); } } } } Or some helper functions might be good. Here's the ones I did: template hasAnnotation(alias f, Attr) { bool helper() { foreach(attr; __traits(getAttributes, f)) static if(is(attr == Attr) || is(typeof(attr) == Attr)) return true; return false; } enum bool hasAnnotation = helper; } template hasValueAnnotation(alias f, Attr) { bool helper() { foreach(attr; __traits(getAttributes, f)) static if(is(typeof(attr) == Attr)) return true; return false; } enum bool hasValueAnnotation = helper; } template getAnnotation(alias f, Attr) if(hasValueAnnotation!(f, Attr)) { auto helper() { foreach(attr; __traits(getAttributes, f)) static if(is(typeof(attr) == Attr)) return attr; assert(0); } enum getAnnotation = helper; } hasAnnotation!(something, Dump) tells you if it is just there hasValueAnnotation tells you if the annoation has a value (enum Dump; won't, but struct Dump { int option; } would). getAnnotation fetches the value. The "something" argument there is a symbol, e.g. __traits(getMember, T, mem). The second argument is the type you're interested in.
Jun 06 2013
On Thursday, 6 June 2013 at 17:50:08 UTC, Chris Williams wrote:...It will work if use "enum" instead of "auto" for storing attribute tuple. If compile-time value is needed you almost always want to store it in enum.
Jun 06 2013