C++ の属性

C++ 標準では、共通の属性セットが定義されています。 また、コンパイラ ベンダーは、ベンダー固有の名前空間内で独自の属性を定義することもできます。 ただし、コンパイラは、標準で定義されている属性を認識するためにのみ必要です。

場合によっては、標準属性がコンパイラ固有の __declspec パラメーターと重複します。 Microsoft C++ では、__declspec(deprecated) を使用する代わりに [[deprecated]] 属性を使用できます。 [[deprecated]] 属性は、準拠しているコンパイラによって認識されます。 dllimportdllexport などの他のすべてのパラメーター __declspec では、今のところ同等の属性は存在しないので、__declspec 構文を引き続き使用する必要があります。 属性は型システムに影響せず、プログラムの意味も変更されません。 コンパイラは、認識しない属性値を無視します。

Visual Studio 2017 バージョン 15.3 以降 (/std:c++17 以降で使用可能): 属性リストのスコープでは、1 つの using 導入子ですべての名前の名前空間を指定できます。

void g() {
    [[using rpr: kernel, target(cpu,gpu)]] // equivalent to [[ rpr::kernel, rpr::target(cpu,gpu) ]]
    do task();
}

C++ 標準属性

C++11 では、属性は、C++ コンストラクト (クラス、関数、変数、ブロックを含むがこれらに限定されません) に追加情報を注釈付けするための標準化された方法を提供します。 属性は、ベンダー固有の場合も異なる場合もあります。 コンパイラは、この情報を使用して情報メッセージを生成したり、属性付きコードをコンパイルするときに特別なロジックを適用したりできます。 コンパイラは認識しない属性を無視します。これは、この構文を使用して独自のカスタム属性を定義できないことを意味します。 属性は二重角かっこで囲まれます。

[[deprecated]]
void Foo(int);

属性は、#pragma ディレクティブ、__declspec() (Visual C++)、__attribute__ (GNU) などのベンダー固有の拡張機能に代わる標準化された代替手段を表します。 ただし、ほとんどの目的で引き続きベンダー固有のコンストラクトを使用する必要があります。 標準では現在、準拠しているコンパイラが認識する必要がある次の属性を指定しています。

[[carries_dependency]]

この属性は [[carries_dependency]] 、関数がスレッド同期のデータ依存関係の順序を伝達することを指定します。 属性を 1 つ以上のパラメーターに適用して、渡された引数が関数本体に依存関係を持ち込むことを指定できます。 属性を関数自体に適用して、戻り値が関数から依存関係を持ち出すことを指定できます。 コンパイラはこの情報を使用して、より効率的なコードを生成できます。

[[deprecated]]

Visual Studio 2015 以降: この属性は [[deprecated]] 、関数が使用を意図していないことを指定します。 または、将来のバージョンのライブラリ インターフェイスに存在しない可能性があります。 この属性は [[deprecated]] 、クラス、typedef-name、変数、非静的データ メンバー、関数、名前空間、列挙型、列挙子、またはテンプレートの特殊化の宣言に適用できます。 コンパイラは、この属性を使用して、クライアント コードが関数を呼び出す際に情報メッセージを生成できます。 Microsoft C++ コンパイラは、項目の使用を [[deprecated]] 検出すると、コンパイラ警告 C4996 を発生させます。

[[fallthrough]]

Visual Studio 2017 以降: (以降で /std:c++17 使用可能)。属性は [[fallthrough]] 、フォールスルー動作が switch 意図されているコンパイラ (またはコードを読んでいるすべてのユーザー) に対するヒントとして、ステートメントのコンテキストで使用できます。 現在、Microsoft C++ コンパイラでは、フォールスルー動作に関する警告は行わないので、この属性はコンパイラの動作に影響しません。

[[likely]]

Visual Studio 2019 バージョン 16.6 以降: (以降で /std:c++20 使用可能)。属性は [[likely]] 、属性付きラベルまたはステートメントのコード パスが代替コードよりも実行される可能性が高いというヒントをコンパイラに指定します。 Microsoft コンパイラでは、[[likely]] 属性はブロックを "ホット コード" としてマークし、内部最適化スコアをインクリメントします。 このスコアのインクリメント量は、速度を最適化する場合は多く、サイズを最適化する場合はそれほど多くありません。 ネット スコアは、インライン化、ループのアンローリング、ベクター化の最適化の可能性に影響します。 [[likely]][[unlikely]] の効果は、ガイド付き最適化のプロファイルに似ていますが、スコープは現在の翻訳単位に限定されています。 ブロックの並べ替えの最適化は、この属性に対してまだ実装されていません。

[[maybe_unused]]

Visual Studio 2017 バージョン 15.3 以降: (以降で /std:c++17 使用可能)。この属性は [[maybe_unused]] 、変数、関数、クラス、typedef、非静的データ メンバー、列挙型、またはテンプレートの特殊化が意図的に使用されないことを指定します。 [[maybe_unused]] とマークされたエンティティが使用されていない場合、コンパイラは警告を出しません。 属性なしで宣言されたエンティティは、後で属性を使用して再宣言できます。その逆も可能です。 エンティティは、[[maybe_unused]] とマークされた最初の宣言が分析された後、および現在の翻訳単位の残りの部分で、マークされたと見なされます。

[[nodiscard]]

Visual Studio 2017 バージョン 15.3 以降: (以降で/std:c++17使用可能)。関数の戻り値が disカード を意図していないことを指定します。 次の例に示すように、警告 C4834 が発生します。

[[nodiscard]]
int foo(int i) { return i * i; }

int main()
{
    foo(42); //warning C4834: discarding return value of function with 'nodiscard' attribute
    return 0;
}

[[noreturn]]

この属性は [[noreturn]] 、関数が返されないように指定します。つまり、常に例外をスローするか終了します。 コンパイラは、[[noreturn]] エンティティのコンパイル ルールを調整できます。

[[unlikely]]

Visual Studio 2019 バージョン 16.6 以降: (以降で /std:c++20 使用可能)。属性は [[unlikely]] 、属性付きラベルまたはステートメントのコード パスが代替コードよりも実行される可能性が低いというヒントをコンパイラに指定します。 Microsoft コンパイラでは、[[unlikely]] 属性はブロックを "コールド コード" としてマークし、内部最適化スコアをデクリメントします。 このスコアのデクリメント量は、サイズを最適化する場合は多く、速度を最適化する場合はそれほど多くありません。 ネット スコアは、インライン化、ループのアンローリング、ベクター化の最適化の可能性に影響します。 ブロックの並べ替えの最適化は、この属性に対してまだ実装されていません。

Microsoft 固有の属性

[[gsl::suppress(rules)]]

Microsoft 固有[[gsl::suppress(rules)]]の属性は、コードでガイドライン サポート ライブラリ (GSL) 規則を適用するチェック者からの警告を抑制するために使用されます。 たとえば、次のコードについて考えます。

int main()
{
    int arr[10]; // GSL warning C26494 will be fired
    int* p = arr; // GSL warning C26485 will be fired
    [[gsl::suppress(bounds.1)]] // This attribute suppresses Bounds rule #1
    {
        int* q = p + 1; // GSL warning C26481 suppressed
        p = q--; // GSL warning C26481 suppressed
    }
}

この例では、次の警告が発生します。

  • C26494 (型規則 5: 常にオブジェクトを初期化します。

  • C26485 (境界規則 3: ポインターの減衰に対する配列がありません。)

  • C26481 (境界規則 1: ポインター算術演算を使用しません。代わりに span を使用してください)。)

最初の 2 つの警告は、CppCoreCheck コード分析ツールをインストールおよびアクティブにしてこのコードをコンパイルすると発生します。 ただし、属性が原因で 3 番目の警告は発生しません。 特定のルール番号を含めず [[gsl::suppress(bounds)]] を作成することで、境界プロファイル全体を抑制することができます。 C++ Core Guidelines は、より優れた、より安全なコードを作成するために設計されています。 suppress 属性を使用すると、必要ないときに警告を簡単にオフにできます。

[[msvc::flatten]]

Microsoft 固有の属性 [[msvc::flatten]] は非常によく [[msvc::forceinline_calls]]似ていますが、同じ場所と同じ方法で使用できます。 違いは、呼び出しが[[msvc::flatten]][[msvc::forceinline_calls]]残らないまで、再帰的に適用されるスコープ内のすべての呼び出しです。 その結果、関数のコード サイズが大きくなり、コンパイラのスループットが増加し、手動で管理する必要があります。

[[msvc::forceinline]]

関数宣言の前に配置すると、Microsoft 固有の属性 [[msvc::forceinline]] の意味 __forceinlineは .

[[msvc::forceinline_calls]]

Microsoft 固有の属性 [[msvc::forceinline_calls]] は、ステートメントまたはブロックの上または前に配置できます。 これにより、インラインヒューリスティックは、そのステートメントまたはブロック内のすべての呼び出しを [[msvc::forceinline]] 試みます。

void f() {
    [[msvc::forceinline_calls]]
    {
        foo();
        bar();
    }
    ...
    [[msvc::forceinline_calls]]
    bar();
    
    foo();
}

への最初の呼び出しと両方のbar呼びfoo出しは、宣言された__forceinlineかのように扱われます。 2 回目の呼び出し foo は.として __forceinline扱われません。

[[msvc::intrinsic]]

この [[msvc::intrinsic]] 属性には、適用される関数に対して 3 つの制約があります。

  • 関数を再帰的にすることはできません。その本体には、パラメーター型から戻り値の型までの return static_cast ステートメントのみを含める必要があります。
  • この関数は、1 つのパラメーターのみを受け取ることができます。
  • /permissive- コンパイラ オプションが必要です。 (以降のオプションは /std:c++20 、既定で示 /permissive- されています)。

Microsoft 固有 [[msvc::intrinsic]] の属性は、パラメーター型から戻り値の型への名前付きキャストとして機能するメタ関数をインライン化するようにコンパイラに指示します。 関数定義に属性が存在する場合、コンパイラはその関数のすべての呼び出しを単純なキャストに置き換えます。 この [[msvc::intrinsic]] 属性は、Visual Studio 2022 バージョン 17.5 プレビュー 2 以降のバージョンで使用できます。 この属性は、その後の特定の関数にのみ適用されます。

このサンプル コードでは、関数にmy_move適用された属性により、[[msvc::intrinsic]]コンパイラは関数の呼び出しを、その本体のインライン静的キャストに置き換えます。

template <typename T>
[[msvc::intrinsic]] T&& my_move(T&& t) { return static_cast<T&&>(t); }

void f() {
    int i = 0;
    i = my_move(i);
}

[[msvc::noinline]]

関数宣言の前に配置すると、Microsoft 固有の属性 [[msvc::noinline]] の意味 declspec(noinline)は .

[[msvc::noinline_calls]]

Microsoft 固有の属性 [[msvc::noinline_calls]] の使用法 [[msvc::forceinline_calls]]は 、 任意のステートメントまたはブロックの前に配置できます。 そのブロック内のすべての呼び出しを強制的にインライン化するのではなく、適用されるスコープのインライン化をオフにする効果があります。

[[msvc::no_tls_guard]]

Microsoft 固有[[msvc::no_tls_guard]]の属性は、DLL 内のスレッド ローカル変数への最初のアクセス時に初期化のチェックを無効にします。 チェックは、Visual Studio 2019 バージョン 16.5 以降のバージョンを使用してビルドされたコードで既定で有効になっています。 この属性は、その後の特定の変数にのみ適用されます。 チェックをグローバルに無効にするには、コンパイラ オプションを/Zc:tlsGuards-使用します。