英語版
このページの英語版を見る

属性

AttributeSpecifier:
    Attribute :
    Attribute DeclarationBlock
Attribute: AlignAttribute AtAttribute DeprecatedAttribute FunctionAttributeKwd LinkageAttribute Pragma VisibilityAttribute abstract auto const final __gshared extern immutable inout override ref return scope shared static synchronized
FunctionAttributeKwd: nothrow pure
AtAttribute: @ disable @ nogc @ live Property @ safe @ system @ trusted UserDefinedAttribute
Property: @ property
DeclarationBlock: DeclDef { DeclDefsopt }

属性は、1つまたは複数の宣言を修正する方法である。 一般的な形式は以下の通りである。

attribute declaration; // 宣言に影響する

attribute:     // 現在のスコープが終了するまで、すべての宣言に影響する
               // 現在のスコープ
  declaration;
  declaration;
  ...

attribute {    // ブロック内のすべての宣言に影響する
  declaration;
  declaration;
  ...
}

リンク属性

LinkageAttribute:
    extern ( LinkageType )
    extern ( C ++ , )
    extern ( C ++ , QualifiedIdentifier )
    extern ( C ++ , NamespaceList )
    extern ( C ++ , class )
    extern ( C ++ , struct )
LinkageType: C C ++ D Windows System Objective - C
NamespaceList: ConditionalExpression ConditionalExpression, ConditionalExpression, NamespaceList

Dは、C関数とオペレーティングシステムのAPI関数を簡単に呼び出す方法を提供する。 両者との互換性は不可欠である。 LinkageTypeは大文字と小文字が区別され、 実装によって拡張可能である(キーワードではない)。CD は必須であり、他のものは 実装に意味があるものである。C++ はC++との限定的な互換性を提供する。 詳細は「C++とのインターフェイス」の ドキュメントを参照のこと。 Objective-C Objective-Cとの互換性を提供しており、 詳細は「Objective-Cとのインターフェイス」のドキュメントを参照のこと。System はWindowsプラットフォームではWindows と同じであり、 他のプラットフォームではC と同じである。

Implementation Note: Win32プラットフォームの場合は、Windows が存在する必要がある。

C関数の呼び出し規約は、 以下によって指定される。

extern (C):
    int foo(); // foo()をCで呼び出す。
extern(C) は、structclass を含むすべての宣言に対して提供できることに 注意すること。ただし、C 側には対応する一致するものがない。その場合、 属性は無視される。この動作は、ネストされた 関数やネストされた変数にも適用される。ただし、static メンバ メソッドおよびstatic ネストされた関数では、extern(C) を追加すると 呼び出し規約は変更されるが、マングリングは変更されない。

D 規約は以下の通り:

extern (D):

Windows APIの規約は:

extern (Windows):
    void *VirtualAlloc(
        void *lpAddress,
        uint dwSize,
        uint flAllocationType,
        uint flProtect
    );

Windowsの規約は、Win32プラットフォーム上でのみC規約と異なり、 ここで stdcall規約と同等となる。

extern キーワードが単独で ストレージクラスとして使用されていることに注意。

C++ ネームスペース

リンク形式extern (C++, QualifiedIdentifier) は、C++ ネームスペースに存在する C++ 宣言を作成する。QualifiedIdentifier は ネームスペースを指定する。

extern (C++, N) { void foo(); }

C++宣言を参照している。

namespace N { void foo(); }

修飾語句を付けても付けなくても参照できる。

foo();
N.foo();

名前空間は、囲むスコープにインポートされる新しい名前付きスコープを作成する。

extern (C++, N) { void foo(); void bar(); }
extern (C++, M) { void foo(); }

void main()
{
    bar();   // OK
    //foo(); // エラー - N.foo()またはM.foo() ?
    M.foo(); // OK
}

QualifiedIdentifier内の複数のドット付き識別子は、ネストされた名前空間を作成する。

extern (C++, N.M) { extern (C++) { extern (C++, R) { void foo(); } } }
N.M.R.foo();

C++宣言を参照している。

namespace N { namespace M { namespace R { void foo(); } } }

align 属性

AlignAttribute:
    align
    align ( AssignExpression )

配置を指定する:

  1. 変数
  2. 構造体フィールド
  3. 共用体フィールド
  4. クラスフィールド
  5. 構造体、共用体、クラス型

align それ自体では デフォルトに設定され、これは、対応するCコンパイラのデフォルトのメンバー整列と一致する。

struct S
{
  align:
    byte a;   // オフセット0に配置
    int b;    // オフセット4に配置
    long c;   // オフセット8に配置
}
static assert(S.alignof == 8);
static assert(S.c.offsetof == 8);
static assert(S.sizeof == 16);

AssignExpressionは、 デフォルト以外のアラインメントが使用される場合の、コンパニオンCコンパイラの動作に一致するアラインメントを指定する。 これは、2のべき乗でなければならない。

値が1の場合は、整列は行われず、 フィールドはまとめてパックされる。

struct S
{
  align (1):
    byte a;   // オフセット0に配置
    int b;    // オフセット1に配置
    long c;   // オフセット5に配置
}
static assert(S.alignof == 1);
static assert(S.c.offsetof == 5);
static assert(S.sizeof == 13);

集約の自然なアラインメントは、そのフィールドの最大のアラインメントである。 アラインメントをアグリゲートの外部で設定することで、これを上書きすることができる。

align (2) struct S
{
  align (1):
    byte a;   // オフセット0に配置
    int b;    // オフセット1に配置
    long c;   // オフセット5に配置
}
static assert(S.alignof == 2);
static assert(S.c.offsetof == 5);
static assert(S.sizeof == 14);

フィールドのアラインメントを設定すると、フィールドのサイズに関係なく、2のべき乗にアラインメントが設定される。

struct S
{
               byte a;  // オフセット0に配置
    align (4)  byte b;  // オフセット4に配置
    align (16) short c; // オフセット16に配置
}
static assert(S.alignof == 16);
static assert(S.c.offsetof == 16);
static assert(S.sizeof == 32);

AlignAttributeは、 関数スコープまたは匿名でない構造体、共用体、クラスに入るときにデフォルトにリセットされ、 そのスコープを抜けると元に戻る。 これは基底クラスから継承されない。

参照:構造体レイアウト

GC 互換性

NewExpressionを使用して割り当てられた参照またはポインタをsize_t の倍数ではない境界で整列しない こと。 ガベージコレクタは、 GCによって割り当てられたオブジェクトへのポインタおよび参照がsize_tバイト境界にあると想定している。

struct S
{
  align(1):
    byte b;
    int* p;
}

static assert(S.p.offsetof == 1);

@safe void main()
{
    S s;
    s.p = new int; // エラー: @safeコードでミスアラインドポインタを変更できない
}
GCが割り当てたオブジェクトへのポインタや参照が xml-ph-0000@deepl.internalバイト境界に整列されていない場合。
Undefined Behavior: GCが割り当てたオブジェクトへのポインタや参照が バイト境界に整列されていない場合。size_t

deprecated 属性

DeprecatedAttribute:
    deprecated
    deprecated ( AssignExpression )

ライブラリ内の機能を廃止する必要がある場合でも、 後方互換性を維持するためにそれを保持しておく必要がある場合がよくある。そのような 宣言はdeprecated としてマークすることができ、

deprecated
{
    void oldFoo();
}

oldFoo();   // 非推奨: 関数test.oldFooは非推奨である

オプションとして、文字列リテラルまたはマニフェスト定数を使用して 、非推奨メッセージに追加情報を提供することができる。

deprecated("Don't use bar") void oldBar();
oldBar();   // 非推奨: 関数test.oldBarは非推奨 - barを使わないでほしい

CTFE対応関数を呼び出したり、マニフェスト定数を使用することも可能である。

import std.format;

enum message = format("%s and all its members are obsolete", Foobar.stringof);
deprecated(message) class Foobar {}
deprecated(format("%s is also obsolete", "This class")) class BarFoo {}

void main()
{
    auto fb = new Foobar();   // 非推奨: class test.Foobarは非推奨 - Foobar
                             // およびそのすべてのメンバは廃止された
    auto bf = new BarFoo();  // 非推奨: class test.BarFooは非推奨  - この
                             // クラスも廃止されている
}

Implementation Note: コンパイラには、 を無視するか、警告を発するか、コンパイル時にエラーとするかを指定するスイッチがあるはずだ。 deprecated

可視性属性

VisibilityAttribute:
    export
    package
    package ( QualifiedIdentifier )
    private
    protected
    public

可視性は、privatepackageprotectedpublic 、またはexport のいずれかの属性である。 DIP22より前の文書では、これらの属性は保護属性と呼ばれることがある。

可視性はシンボル名の検索に関与する。

export 属性

export シンボルが実行可能ファイル、共有ライブラリ、または DLL の外部からアクセスできることを意味する。 シンボルは、実行可能ファイル、共有ライブラリ、または DLL で定義された場所からエクスポートされ、別の実行可能ファイル、共有ライブラリ、または DLL でインポートされる。

export シンボルの定義に適用された場合は、それをエクスポートする。 が シンボルの宣言に適用された場合は、それをインポートする。 が適用されない限り、変数は定義である。export extern

export int x = 3;    // 定義、`x`のエクスポート
export int y;        // 定義、`y`のエクスポート
export extern int z; // 宣言、`z`のインポート

export __gshared h = 3;        // 定義、`h`のエクスポート
export __gshared i;            // 定義、`i`のエクスポート
export extern __gshared int j; // 宣言、`j`のインポート

本体のある関数は定義であり、本体のないものは宣言である。

export void f() { }  // 定義, `f`のエクスポート
export void g();     // 宣言, `g`のインポート

Windows用語では、dllexportはDLLからシンボルをエクスポートすることを意味し、dllimportは DLLまたは実行可能ファイルがDLLからシンボルをインポートすることを意味する。

package 属性

package private を拡張し、パッケージのメンバーが 同じパッケージ内の他のモジュール内のコードからアクセスできるようにする。 識別子が指定されていない場合、これは最も内側のパッケージのみに適用される。 または、モジュールがパッケージ内にネストされていない場合は、 をデフォルトとする。 private

package ドット区切りの識別子リスト形式のオプションパラメータを指定できる。 これは修飾パッケージ名として解決される。パッケージはモジュールの 親パッケージ、またはその祖先パッケージのいずれかでなければならない。このパラメータが指定されている場合、シンボルは 指定されたパッケージとそのすべての子孫で表示される。

private 属性

private の可視性を持つシンボルは、 同じモジュール内からのみアクセスできる。 プライベートメンバ関数は暗黙的に final オーバーライドすることはできません。

protected 属性

protected クラス(およびテンプレート化された関数)内部でのみ適用され、 同じモジュールのメンバー、または派生クラスによってのみシンボルを参照できることを意味する。 派生クラスのメンバー関数を通じてプロテクトされたインスタンスメンバーにアクセスする場合、 そのメンバーは 暗黙的に 'this' と同じ型にキャストできるオブジェクトインスタンスに対してのみアクセスできる。 モジュールメンバーは無効である。 protected

public 属性

public 実行可能ファイル内のコードはすべてメンバーを参照できることを意味する。 これはデフォルトの可視性属性である。

変更可能属性

const 属性

const 型修飾子は、 宣言されたシンボルの型をT からconst(T) に変更する。ここで、T は、const が指定されていない場合に導入されたシンボルに対して指定(または推論)された型である。

const int foo = 7;
static assert(is(typeof(foo) == const(int)));

const double bar = foo + 6;
static assert(is(typeof(bar) == const(double)));
xml-ph-0000@deepl.internal
class C
{
    const void foo();
    const
    {
        void bar();
    }
    void baz() const;
}
pragma(msg, typeof(C.foo)); // const void()
pragma(msg, typeof(C.bar)); // const void()
pragma(msg, typeof(C.baz)); // const void()

static assert(is(typeof(C.foo) == typeof(C.bar)) &&
              is(typeof(C.bar) == typeof(C.baz)));

参照:修飾された型の返却方法

immutable 属性

immutable 属性は、T からimmutable(T) に型を変更する。 これは、const と同じ方法である。参照:

inout 属性

inout 属性はT からinout(T) に型を変更する。 これは、const と同じ方法である。

共有ストレージの属性

shared 属性

参照 shared

__gshared 属性

デフォルトでは、不変ではないグローバル宣言はスレッドローカルストレージに格納される。 グローバル変数が__gshared属性でマークされている場合、その値はすべてのスレッドで共有される。

int foo;            // 各スレッドはfooの排他的コピーを持つ。
__gshared int bar;  // barはすべてのスレッドで共有される。

__gshared メンバ変数やローカル変数にも適用できる。 これらの場合、 は と同等であるが、 ただし、変数はスレッドローカルではなく、すべてのスレッドで共有される。__gshared static

class Foo
{
    __gshared int bar;
}

int foo()
{
    __gshared int bar = 0;
    return bar++; // スレッドセーフではない。
}

警告: xml-ph-0000@deepl.internalは、属性とは異なり、 shared属性とは異なり、__gshared は データ競合やその他のマルチスレッドの同期に関する問題に対する 保護機能を提供しない。__gshared とマークされた変数へのアクセスが正しく同期されるようにすることは、プログラマーの責任である。

__gshared @safe コードでは許可されていない。

synchronized 属性

「同期クラス」を参照。

@disable 属性

属性でマークされた宣言への参照は、 コンパイル時にエラーを引き起こす。これは、特定の 操作やオーバーロードをコンパイル時に明示的に許可しないようにするために使用できる。

@disable 属性が指定された宣言を参照すると、 コンパイル時にエラーが発生する。これは、 実行時にエラーが発生するのを待つのではなく、コンパイル時に特定の操作やオーバーロードを明示的に禁止する ために使用できる。

@disable void foo() { }
xml-ph-0000@deepl.internal
void main() { foo(); /* error, foo is disabled */ }

@disable this(); 構造体内ではデフォルトのコンストラクションが禁止される。

構造体のコピーコンストラクタを無効にすると、 その構造体はコピーできなくなる。

、 xml-ph-0000@deepl.internal、xml-ph-0001@deepl.internal 属性

@safe@trusted@system 属性

関数安全を参照。

システム変数

@system とマークされた変数は、@safe コードからアクセスできない。

@system int* p;

struct S
{
    @system int i;
}

void main() @safe
{
    int x = *p; // error with `-preview=systemVariables`, deprecation otherwise

    S s;
    s.i = 0; // ditto
}
xml-ph-0000@deepl.internalxml-ph-0000@deepl.internal

関数属性

@nogc 属性

No-GC関数を参照。

@property 属性

プロパティ関数」を参照。

nothrow 属性

Nothrow関数を参照。

pure 属性

純粋関数を参照。

ref 属性

ref ストレージクラスを参照。

return 属性

static 属性

static 属性は、型、関数、データに適用される。static は、他の宣言に適用される場合は無視される。

集約型内部では、static 宣言はオブジェクトの特定のインスタンスには適用されず、 オブジェクトの型に適用される。 つまり、this 参照は存在しないということである。

class Foo
{
    static int x;
    static int bar() { return x; }
    int foobar() { return 7; }
}

Foo.x = 6; // インスタンスは必要ない
assert(Foo.bar() == 6);
//Foo.foobar(); // エラー、Fooのインスタンスがない。

Foo f = new Foo;
assert(f.bar() == 6);
assert(f.foobar() == 7);

静的メソッドは決して仮想ではない。

静的データはオブジェクトごとに1つではなく、スレッドごとに1つのインスタンスを持つ。

静的ネスト関数 またはは、 親スコープ内の変数にアクセスできない。

関数内部では、静的ローカル変数は関数が返された後も保持される。

Staticは、C言語における「ファイルローカル」という追加の意味を持たない。 その機能を実現するには、D言語の属性を使用する。 private Dの属性を使用して、それを実現する。 例えば:

module foo;
int x = 3;         // xはグローバルである。
private int y = 4; // yはモジュールfooのローカル変数である
xml-ph-0000@deepl.internalxml-ph-0000@deepl.internal

auto 属性

auto 属性は、他の属性がなく 型推論が必要な場合に

auto i = 6.8;   // iをdoubleとして宣言する

関数では、auto 属性は戻り値の型推論を意味する。 "auto関数"を参照。

scope 属性

scope 属性は、変数のポインタ値が、その変数が宣言されたスコープから外に出ないことを意味する。

変数の型に間接参照が含まれない場合、scope 属性は無視される。

グローバル変数に適用された場合、scope も無視される。なぜなら、ポインタがエスケープできるスコープはグローバルスコープより大きいものはないからだ。

scope int* x; // スコープは無視され、グローバル変数となる

void main()
{
    // scope static int* x;  // スコープとstaticの両方にはできない
    scope float y;           // スコープは無視され、遠まわしな表現をしない
    scope int[2] z;          // スコープは無視され、静的配列は値型である
    scope int[] w;           // スコープ動的配列
}
間接参照を持つ型のローカル変数に適用された場合、 その値はより長い寿命を持つ変数に割り当てられない可能性がある。

間接参照を持つ型のローカル変数に適用した場合、 その変数の値は、より長い寿命を持つ変数に割り当てられない可能性がある。

また、より長い寿命を持つ変数に暗黙的に代入する他の操作も許可されない。

scope 属性は変数宣言の一部であり、型ではない。また、これは間接参照の第一レベルにのみ適用される。 例えば、変数をスコープポインタの動的配列として宣言することはできない。なぜなら、scope は配列自体の.ptrのみに適用され、その要素には適用されないからだ。scope は、以下のようにさまざまな型に影響する。

Type of local variableWhat scope applies to
すべての基本データ型なし
ポインタ T*ポインタ値
動的配列 T[].ptr を要素に
静的配列 T[n]各要素T
連想配列 K[V]ポインタを処理系定義の構造体へ
struct またはunion各メンバ変数への
function ポインタポインタ値
デリゲート.funcptr.ptr (クロージャコンテキスト)の両方のポインタ値を
class またはinterfaceクラス参照
列挙型基本型
struct S
{
    string str; // 注釈: string = immutable(char)[]
    string* strPtr;
}

string escape(scope S s, scope S* sPtr, scope string[2] sarray, scope string[] darray)
{
    return s.str;        // 無効、スコープは構造体メンバに適用される
    return *s.strPtr;    // 有効、scope構造体メンバーは再参照される
    return sPtr.str;     // 有効、構造体ポインタは再参照される
    return *sPtr.strPtr; // 有効、2つのポインタが参照解除される
    return sarray[0];    // 無効、スコープは静的配列要素に適用される
    return sarray[1];    // 無効、同上
    return darray[0];    // 有効、スコープは要素ではなく配列ポインタに適用される
}

スコープ値

scope 変数の値、またはスタック割り当てメモリを指す生成された値を「scope 値」と呼ぶ。 このような値は、スタティック配列をスライスするか、 または スタックに割り当てられた(または割り当てられる可能性がある)変数へのポインタを作成することで生成される。

Typesafe 可変長引数関数からの可変長引数もスコープ値である。 引数はスタック上に渡されるためである。

ローカル変数にscope の値が代入される場合、その変数に明示的な型が指定されていてauto キーワードを使用していない場合でも、scope と推論される。

@safe:
ref int[2] identity(return ref int[2] x) {return x;}

int* escape(int[2] y, scope int* z)
{
    int x;

    auto  xPtr  = &x;            // `scope int*`と推論される
    int[] yArr  = identity(y)[]; // `scope int[]`と推論される
    int*  zCopy = z;             // `scope int*`と推論される

    return zCopy; // エラー
}

void variadic(int[] a...)
{
    int[] x = a; // `scope int[]`と推論される
}

void main()
{
    variadic(1, 2, 3);
}
struct S
{
    int x;

    // このメソッドは、スタックに確保されたSのインスタンスに対して呼び出すことができる
    void f()
    {
        int* p = &x; // `scope int* p`と推論される
        int* q = &this.x; // 等価
    }
}

スコープパラメータは、スコープローカル変数と同じように扱われるが、 関数に関数属性推論がある場合は、それらを返すことが許可される。 その場合、それらはリターンスコープパラメータとして推論される。

scope クラスインスタンス

クラスインスタンスを直接割り当てるために使用される場合、scope 変数はRAII (リソース取得は初期化である)プロトコルを意味する。 これは、オブジェクトの参照がスコープ外に出たときに、オブジェクトのデストラクタが自動的に呼び出されることを意味する。 デストラクタは、 例外がスローされてスコープから抜けた場合でも呼び出されるため、scope

クラスがnew で構築され、scope のローカル変数に割り当てられる場合、 スタック上に割り当てられ、@nogc のコンテキストで許可される可能性がある。

scope クラスの変数が同時にスコープから外れるものが複数ある場合、 そのデストラクタは、 変数が構築された順序と逆の順序で呼び出される。

クラス型のscope 変数への代入は、 初期化以外では許可されていない。なぜなら、そうすると変数の適切な破棄が複雑になるからだ。

import core.stdc.stdio : puts;

class C
{
    ~this() @nogc { puts(__FUNCTION__); }
}

void main() @nogc
{
    {
        scope c0 = new C(); // スタックに割り当てられる
        scope c1 = new C();

        //c1 = c0; // エラー: スコープ変数を結合し直すことができない

        // ここでは`c1`と`c0`のデストラクタが順に呼び出される
    }
    puts("bye");
}
deeplxml-ph-0000@deepl.internal

OOP 属性

abstract 属性

抽象クラスは派生クラスによってオーバーライドされなければならない。 抽象メンバ関数を宣言すると、クラスが抽象クラスとなる。

final 属性

override 属性

仮想関数」を参照。

属性

@mustuse 属性

@mustuse 属性は、Dランタイムモジュールで定義されたコンパイラ認識の ユーザー定義属性である。 core.attribute

式は、以下のいずれかが真である場合にのみ破棄されるとみなされる。

以下のいずれかが真である場合、式は破棄されるとみなされる。

以下のすべてが真である場合、式を破棄することはコンパイル時のエラーである。

「代入式」とは、 単純代入式または 代入 演算子式を意味する。

「インクリメント式」とは、演算子が++であるUnaryExpressionまたはPostfixExpressionを意味する。

「減算式」とは、演算子が--であるUnaryExpressionまたは PostfixExpressionを意味する。

@mustuse を関数宣言に結び付けること、またはstruct またはunion 宣言以外の集約宣言に結び付けることは、コンパイル時のエラーとなる。 この規則の目的は、将来的な拡張の可能性を考慮して、そのような用法を確保することである。

ユーザー定義属性

UserDefinedAttribute:
    @ ( TemplateArgumentList )
    @ TemplateSingleArgument
    @ Identifier ( NamedArgumentListopt )
    @ TemplateInstance
    @ TemplateInstance ( NamedArgumentListopt )

ユーザー定義属性(UDA)は、宣言に付加できるコンパイル時の注釈である。 これらの属性は、コンパイル時に問い合わせ、抽出、操作することができる。 これには実行時コンポーネントは存在しない。

ユーザー定義属性は、以下を使用して定義される。
@(3) int a; // 値の引数
@("string", 7) int b; // 複数の値

// コンパイル時定数を使用する
enum val = 3;
@val int a2; // `a`と同じ属性を持つ

enum Foo;
@Foo int c; // 型名の属性

struct Bar
{
    int x;
}
@Bar() int d; // 型インスタンス
@Bar(3) int e; // イニシャライザを使った型インスタンス

e Bar の場合、この属性は、 静的に初期化される 引数を使用する

宣言のスコープに複数のUDAが存在する場合、それらは連結される。

@(1)
{
    @(2) int a;         // UDA (1, 2)を持つ
    @("string") int b;  // UDA (1, "string")を持つ
}

関数パラメータはUDAを持つことができる。

xml-ph-0000@deepl.internal
void f(@(3) int p);

__traits(getAttributes)

UDAは、 を使用して コンパイル時のシーケンスに抽出できる。

UDAは、__traits を使用してコンパイル時のシーケンスに抽出できる。

@('c') string s;
pragma(msg, __traits(getAttributes, s)); // tuple('c')を表示する。

シンボルにユーザー定義の属性がない場合は、空のシーケンスが返される。 結果は、コンパイル時のシーケンスと同様に使用できる。つまり、インデックス付けや テンプレートパラメータとして渡すことができるなどである。

enum e = 7;
@("hello") struct SSS { }
@(3)
{
    @(4) @e @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, a)); // tuple()を表示する
pragma(msg, __traits(getAttributes, typeof(a))); // タプル("hello")を表示する

使用法

もちろん、UDAの真価は、特定の値を持つユーザー定義型を作成できることにある。 基本型の属性値を持つだけではスケールしない。 xml-ph-0000@deepl.internal

属性が値であるか型であるかはユーザー次第であり、後から 追加された属性が以前の属性を上書きするかどうかは、ユーザーが属性をどのように解釈するかによって決まる 。

テンプレート

UDAがテンプレート宣言に添付されている場合、そのUDAは自動的に そのテンプレートのインスタンスのすべての直接メンバに添付される。それらのメンバのいずれかが テンプレートである場合、このルールは再帰的に適用される。

@("foo") template Outer(T)
{
    struct S
    {
        int x;
    }
    int y;
    void fun() {}
    @("bar") template Inner(U)
    {
        int z;
    }
}

pragma(msg, __traits(getAttributes, Outer!int.S));
// tuple("foo")を表示する
pragma(msg, __traits(getAttributes, Outer!int.S.x));
// tuple()を表示する
pragma(msg, __traits(getAttributes, Outer!int.y));
// tuple("foo")を表示する
pragma(msg, __traits(getAttributes, Outer!int.fun));
// tuple("foo")を表示する
pragma(msg, __traits(getAttributes, Outer!int.Inner));
// tuple("foo", "bar")を表示する
pragma(msg, __traits(getAttributes, Outer!int.Inner!int.z));
// tuple("foo", "bar")を表示する

UDAはテンプレートパラメータに添付できない。