UDA(User Defined Attribute)

UDA(User Defined Attribute、ユーザー定義属性)の使用例についてまとめます。
Examples: UDA取得の例です
import std : hasUDA, AliasSeq;

// 変数宣言の前にUDAを書くことができます。
@(1) int x;
assert(__traits(getAttributes, x) == AliasSeq!(1));

@("test") string y;
assert(__traits(getAttributes, y) == AliasSeq!("test"));

// 無名のenumを作成することでUDAを作成できます。
enum MyUDA;
@MyUDA double z;
assert(hasUDA!(z, MyUDA));
Examples: 特定のUDAを持ったメンバー抽出の例です
import std : getSymbolsByUDA;

// 構造体のメンバーにUDAを持たせることも可能です。
enum MyUDA;
struct S {
    @MyUDA int x = 3;
    float y = 4;
    @MyUDA ubyte z = 5;
}

// 構造体SのメンバのうちMyUDAを持つメンバーはxとzです。
assert(getSymbolsByUDA!(S, MyUDA)[0].stringof == "x");
assert(getSymbolsByUDA!(S, MyUDA)[1].stringof == "z");

// 構造体の各メンバーは通常通りの初期値を持ちます。
S s;
assert(s.x == 3);
assert(s.y == 4);
assert(s.z == 5);

// UDAを用いて特定のメンバーにのみ0を代入します。
static foreach (mem; getSymbolsByUDA!(S, MyUDA))
    __traits(getMember, s, mem.stringof) = 0;
assert(s.x == 0);
assert(s.y == 4);
assert(s.z == 0);
Examples: toStringの自動生成の例です
import std : hasUDA, to, join, format;

template ImplToString()
{
    string toString()
    {
        string[] strs;
        static foreach (mem; __traits(allMembers, typeof(this)))
        {
            static if (__traits(hasMember, typeof(this), mem)
                    && hasUDA!(__traits(getMember, typeof(this), mem), printable))
            {
                strs ~= mem ~ ":" ~ __traits(getMember, typeof(this), mem).to!string;
            }
        }
        return strs.join(",").format!"{%s}";
    }
}

enum printable;

struct A
{
    @printable
    {
        int x;
        float y;
        int[2] z;
    }
    short nonPrintableMember;
    mixin ImplToString;
}

A a = {
    x : 3,
    y : 4.5,
    z : [1, 2],
    nonPrintableMember : 34
};
assert(a.to!string == `{x:3,y:4.5,z:[1, 2]}`);
Examples: 関数の引数に付与されたUDAを取得する例です
import std.traits : Parameters;

int square(@("Some description") int x)
{
    return x * x;
}

alias PT = Parameters!square;

// PT[0] を取得すると引数の型である int が取得されるため、スライスを取るのがポイントです
enum desc = __traits(getAttributes, PT[0 .. 1]);

// 結果は複数ある可能性があるため、タプルから配列のように取り出します
assert(desc[0] == "Some description");