Пользовательские атрибуты (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