名稱空間
變體
操作

屬性說明符序列 (C++11 起)

來自 cppreference.com
< cpp‎ | 語言
 
 
C++ 語言
 
 
屬性
(C++23)
(C++11)(直至 C++26)
(C++14)
(C++20)
(C++17)
(C++11)
(C++20)
 

引入用於型別、物件、程式碼等的實現定義屬性。

目錄

[編輯] 語法

[[ attribute-list ]] (C++11 起)
[[ using attribute-namespace : attribute-list ]] (C++17 起)

其中 attribute-list 是由零個或多個 attribute 組成的逗號分隔序列(可能以省略號 ... 結尾,表示包擴充套件

識別符號 (1)
attribute-namespace :: identifier (2)
identifier ( argument-list(可選) ) (3)
attribute-namespace :: identifier ( argument-list(可選) ) (4)

其中 attribute-namespace 是一個 identifierargument-list 是一個標記序列,其中圓括號、方括號和花括號是平衡的 (balanced-token-seq)。

1) 簡單屬性,例如 [[noreturn]]
2) 帶名稱空間的屬性,例如 [[gnu::unused]]
3) 帶引數的屬性,例如 [[deprecated("because")]]
4) 既有名稱空間又有引數列表的屬性。

如果 using namespace: 出現在屬性列表的開頭,則屬性列表中的其他屬性不能指定名稱空間:using 中指定的名稱空間適用於所有這些屬性。

[[using CC: opt(1), debug]] // same as [[CC::opt(1), CC::debug]]
[[using CC: CC::opt(1)]] // error: cannot combine using and scoped attribute
(C++17 起)

[編輯] 說明

屬性為實現定義的語言擴充套件提供了統一的標準語法,例如 GNU 和 IBM 語言擴充套件 __attribute__((...))、Microsoft 擴充套件 __declspec() 等。

屬性幾乎可以在 C++ 程式的任何地方使用,並且可以應用於幾乎所有內容:型別、變數、函式、名稱、程式碼塊、整個翻譯單元,儘管每個特定屬性僅在實現允許的範圍內有效:[[expect_true]] 可能是一個只能與 if 一起使用,而不能與類宣告一起使用的屬性。[[omp::parallel()]] 可能是一個適用於程式碼塊或 for 迴圈的屬性,但不能用於 int 型別等(請注意,這兩個屬性是虛構示例,有關標準和一些非標準屬性,請參閱下文)。

在宣告中,屬性可以出現在整個宣告之前,也可以直接出現在宣告的實體名稱之後,在這種情況下它們會合並。在大多數其他情況下,屬性應用於直接前面的實體。

alignas 說明符是屬性說明符序列的一部分,儘管它具有不同的語法。它可以出現在 [[...]] 屬性出現的地方,並可以與它們混合使用(前提是在允許 alignas 的地方使用)。

兩個連續的左方括號標記 ([[) 只能在引入屬性說明符或在屬性引數內部時出現。

void f()
{
    int y[3];
    y[[] { return 0; }()] = 1;  // error
    int i [[cats::meow([[]])]]; // OK
}

除了下面列出的標準屬性外,實現還可以支援具有實現定義行為的任意非標準屬性。所有實現未知的屬性都會被忽略,而不會導致錯誤。(C++17 起)

不帶 attribute-namespace 的屬性以及其名稱為 stdstd 後跟一個或多個數字的 attribute-namespace 保留用於未來的標準化。也就是說,每個非標準屬性都位於實現提供的 attribute-namespace 中,例如 [[gnu::may_alias]][[clang::trivial_abi]][[msvc::noop_dtor]]

(C++20 起)

[編輯] 標準屬性

以下屬性由 C++ 標準定義。

標準屬性不能在語法上被忽略:它們不能包含語法錯誤,必須應用於正確的目標,並且引數中的實體必須是 ODR-use

標準屬性也不能在語義上被忽略:移除特定標準屬性的所有例項後的行為,對於帶有該屬性的原始程式而言,仍將是符合規範的行為。

(C++11)
指示函式不返回
(屬性說明符)[編輯]
(C++11)(C++26 中移除)
指示在 release-consume std::memory_order 中,依賴鏈在函式內外傳播
(屬性說明符)[編輯]
[[deprecated]][[deprecated("reason")]]
(C++14)(C++14)
指示允許使用此屬性宣告的名稱或實體,但由於某些 reason 而不鼓勵使用
(屬性說明符)[編輯]
(C++17)
指示從前一個 case 標籤的直落是故意的,不應被警告直落的編譯器診斷
(屬性說明符)[編輯]
(C++17)
抑制編譯器關於未使用實體的警告(如果有)
(屬性說明符)[編輯]
[[nodiscard]][[nodiscard("reason")]]
(C++17)(C++20)
鼓勵編譯器在返回值被丟棄時發出警告
(屬性說明符)[編輯]
(C++20)(C++20)
指示編譯器應最佳化語句執行路徑比其他任何執行路徑更有可能或更不可能的情況
(屬性說明符)[編輯]
指示非靜態資料成員不必具有與其類中所有其他非靜態資料成員不同的地址
(屬性說明符)[編輯]
[[assume(expression)]]
(C++23)
指定 expression 在給定點將始終評估為 true
(屬性說明符)[編輯]
(C++26)
指定如果物件未初始化,則它具有不確定值
(屬性說明符)[編輯]
指示應最佳化函式定義,以從同步語句中呼叫
(屬性說明符)[編輯]

[編輯] 注意

給定平臺上每個單獨屬性的存在可以透過 __has_cpp_attribute 預處理器宏進行檢查。

功能測試宏 標準 特性
__cpp_attributes 200809L (C++11) 屬性
__cpp_namespace_attributes 201411L (C++17) 用於名稱空間的屬性

[編輯] 示例

[[gnu::always_inline]] [[gnu::hot]] [[gnu::const]] [[nodiscard]]
inline int f(); // declare f with four attributes
 
[[gnu::always_inline, gnu::const, gnu::hot, nodiscard]]
int f(); // same as above, but uses a single attr specifier that contains four attributes
 
// C++17:
[[using gnu : const, always_inline, hot]] [[nodiscard]]
int f[[gnu::always_inline]](); // an attribute may appear in multiple specifiers
 
int f() { return 0; }
 
int main() {}

[編輯] 缺陷報告

下列更改行為的缺陷報告追溯地應用於以前出版的 C++ 標準。

缺陷報告 應用於 釋出時的行為 正確的行為
CWG 2079 C++11 [[ 不能出現在屬性引數內部 允許
CWG 2538 C++11 不清楚標準屬性是否可以在語法上被忽略 已禁止
CWG 2695 C++11 不清楚標準屬性是否可以在語義上被忽略 已禁止
P2156R1 C++11 每個標準屬性都要求在 attribute-list 中最多出現一次 未要求

[編輯] 另請參閱

__has_cpp_attribute - 檢查屬性的存在
C 文件 用於 屬性說明符序列

[編輯] 外部連結

1.  GCC 中的屬性。這些屬性可以作為 [[gnu::...]] 使用,參見 SO
2.  Clang 中的屬性.
3.  MSVC 中的屬性.