Пользовательские атрибуты (User-Defined Attributes, UDA) – это выражения времени компиляции, которые можно добавить к объявлению чего-либо. Затем эти атрибуты можно запрашивать, извлекать и изменять во время компиляции. Для них нет исполняемого компонента.
Пользовательский атрибут выглядит, например, так:
@(3) int a;
@("string", 7) int b;
enum Foo;
@Foo int c;
struct Bar
{
int x;
}
@Bar(3) int d;Если в области действия объявления есть несколько UDA, они объединяются:
@(1)
{
@(2) int a; // имеет UDA (1, 2)
@("string") int b; // имеет UDA (1, "string")
}Пользовательские атрибуты могут быть извлечены в кортеж выражения с помощью __traits:
@('c') string s;
pragma(msg, __traits(getAttributes, s)); // выведет tuple('c')Если для символа нет определенных пользователем атрибутов, возвращается пустой кортеж. Кортеж выражения можно превратить в управляемый кортеж:
enum EEE = 7;
@("hello") struct SSS { }
@(3) { @(4) @EEE @SSS int foo; }
alias TP = __traits(getAttributes, foo);
pragma(msg, TP); // выведет tuple(3, 4, 7, (SSS))
pragma(msg, TP[2]); // выведет 7Конечно, для объявления можно использовать типы кортежей:
TP[3] a; // a объявлен как SSS
Атрибут имени типа не совпадает с атрибутом переменной:
pragma(msg, __traits(getAttributes, typeof(a))); // выведет tuple("hello")Настоящая ценность UDA – это возможность создавать определяемые пользователем типы с конкретными значениями. Значения атрибутов базовых типов не масштабируются. Кортежами атрибутов можно управлять, как и любым другим кортежем, и их можно передать в качестве списка аргументов в шаблон.
Являются ли атрибуты значениями или типами, зависит от пользователя, и будут ли более поздние атрибуты накапливаться или переопределяться более ранними, также зависит от того, как пользователь их интерпретирует.
UDA нельзя привязать к параметрам шаблона.
Источник: User-Defined Attributes