@@ -1020,29 +1020,40 @@ $(GNAME UserDefinedAttribute):
1020
1020
)
1021
1021
1022
1022
$(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
1024
1024
to a declaration. These attributes can then be queried, extracted, and manipulated
1025
1025
at compile time. There is no runtime component to them.
1026
1026
)
1027
1027
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
1029
1033
1034
+ $(SPEC_RUNNABLE_EXAMPLE_COMPILE
1030
1035
---
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`
1035
1042
1036
1043
enum Foo;
1037
- @Foo int c;
1044
+ @Foo int c; // type name attribute
1038
1045
1039
1046
struct Bar
1040
1047
{
1041
1048
int x;
1042
1049
}
1043
-
1044
- @Bar(3) int d;
1050
+ @Bar() int d; // type instance
1051
+ @Bar(3) int e; // type instance using initializer
1045
1052
---
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.)
1046
1057
1047
1058
$(P
1048
1059
If there are multiple UDAs in scope for a declaration, they are concatenated:
@@ -1056,8 +1067,16 @@ struct Bar
1056
1067
}
1057
1068
---
1058
1069
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
+
1059
1077
$(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):
1061
1080
)
1062
1081
1063
1082
---
@@ -1066,15 +1085,19 @@ pragma(msg, __traits(getAttributes, s)); // prints tuple('c')
1066
1085
---
1067
1086
1068
1087
$(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.
1071
1091
)
1072
1092
1073
1093
$(SPEC_RUNNABLE_EXAMPLE_COMPILE
1074
1094
---
1075
- enum EEE = 7;
1095
+ enum e = 7;
1076
1096
@("hello") struct SSS { }
1077
- @(3) { @(4) @EEE @SSS int foo; }
1097
+ @(3)
1098
+ {
1099
+ @(4) @e @SSS int foo;
1100
+ }
1078
1101
1079
1102
alias TP = __traits(getAttributes, foo);
1080
1103
@@ -1084,7 +1107,7 @@ pragma(msg, TP[2]); // prints 7
1084
1107
)
1085
1108
1086
1109
$(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:
1088
1111
)
1089
1112
1090
1113
---
@@ -1096,14 +1119,15 @@ TP[3] a; // a is declared as an SSS
1096
1119
)
1097
1120
1098
1121
---
1122
+ pragma(msg, __traits(getAttributes, a)); // prints tuple()
1099
1123
pragma(msg, __traits(getAttributes, typeof(a))); // prints tuple("hello")
1100
1124
---
1101
1125
1126
+ $(H3 $(LNAME2 uda-usage, Usage))
1127
+
1102
1128
$(P
1103
1129
Of course, the real value of UDAs is to be able to create user-defined types with
1104
1130
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.
1107
1131
)
1108
1132
1109
1133
$(P
0 commit comments