@@ -1020,29 +1020,40 @@ $(GNAME UserDefinedAttribute):
10201020)
10211021
10221022 $(P
1023- User-Defined Attributes (UDA) are compile-time expressions that can be attached
1023+ User-Defined Attributes (UDA) are compile-time annotations that can be attached
10241024 to a declaration. These attributes can then be queried, extracted, and manipulated
10251025 at compile time. There is no runtime component to them.
10261026 )
10271027
1028- A user-defined attribute looks like:
1028+ A user-defined attribute is defined using:
1029+ * Compile-time expressions
1030+ * A named manifest constant
1031+ * A type name
1032+ * A type to instantiate using a compile-time argument list
10291033
1034+ $(SPEC_RUNNABLE_EXAMPLE_COMPILE
10301035---
1031- @(3) int a;
1032- ---
1033- ---
1034- @("string", 7) int b;
1036+ @(3) int a; // value argument
1037+ @("string", 7) int b; // multiple values
1038+
1039+ // using compile-time constant
1040+ enum val = 3;
1041+ @val int a2; // has same attribute as `a`
10351042
10361043enum Foo;
1037- @Foo int c;
1044+ @Foo int c; // type name attribute
10381045
10391046struct Bar
10401047{
10411048 int x;
10421049}
1043-
1044- @Bar(3) int d;
1050+ @Bar() int d; // type instance
1051+ @Bar(3) int e; // type instance using initializer
10451052---
1053+ )
1054+ $(P For `e`, the attribute is an instance of struct `Bar` which is
1055+ $(DDSUBLINK spec/struct, static_struct_init, statically initialized)
1056+ using its argument.)
10461057
10471058 $(P
10481059 If there are multiple UDAs in scope for a declaration, they are concatenated:
@@ -1056,8 +1067,16 @@ struct Bar
10561067}
10571068---
10581069
1070+ $(P A function parameter can have a UDA:)
1071+ ---
1072+ void f(@(3) int p);
1073+ ---
1074+
1075+ $(H3 $(LNAME2 getAttributes, `__traits(getAttributes)`))
1076+
10591077 $(P
1060- UDAs can be extracted into an expression tuple using $(D __traits):
1078+ UDAs can be extracted into a
1079+ $(DDSUBLINK spec/template, variadic-templates, compile-time sequence) using $(D __traits):
10611080 )
10621081
10631082---
@@ -1066,15 +1085,19 @@ pragma(msg, __traits(getAttributes, s)); // prints tuple('c')
10661085---
10671086
10681087 $(P
1069- If there are no user-defined attributes for the symbol, an empty tuple is returned.
1070- The expression tuple can be turned into a manipulatable tuple:
1088+ If there are no user-defined attributes for the symbol, an empty sequence is returned.
1089+ The result can be used just like any compile-time sequence - it can be indexed,
1090+ passed as template parameters, etc.
10711091 )
10721092
10731093$(SPEC_RUNNABLE_EXAMPLE_COMPILE
10741094---
1075- enum EEE = 7;
1095+ enum e = 7;
10761096@("hello") struct SSS { }
1077- @(3) { @(4) @EEE @SSS int foo; }
1097+ @(3)
1098+ {
1099+ @(4) @e @SSS int foo;
1100+ }
10781101
10791102alias TP = __traits(getAttributes, foo);
10801103
@@ -1084,7 +1107,7 @@ pragma(msg, TP[2]); // prints 7
10841107)
10851108
10861109 $(P
1087- Of course the tuple types can be used to declare things:
1110+ Any types in the sequence can be used to declare things:
10881111 )
10891112
10901113---
@@ -1096,14 +1119,15 @@ TP[3] a; // a is declared as an SSS
10961119 )
10971120
10981121---
1122+ pragma(msg, __traits(getAttributes, a)); // prints tuple()
10991123pragma(msg, __traits(getAttributes, typeof(a))); // prints tuple("hello")
11001124---
11011125
1126+ $(H3 $(LNAME2 uda-usage, Usage))
1127+
11021128 $(P
11031129 Of course, the real value of UDAs is to be able to create user-defined types with
11041130 specific values. Having attribute values of basic types does not scale.
1105- The attribute tuples can be manipulated like any other tuple, and can be passed as
1106- the argument list to a template.
11071131 )
11081132
11091133 $(P
0 commit comments