属性说明符序列 (C++11 起)

出自cppreference.com


 
 
C++ 語言
 
 
屬性
(C++23)
(C++11)(C++26 前)
(C++14)
(C++20)
(C++17)
(C++11)
(C++20)
 

為類型、對象、代碼等引入由實現定義的屬性。

語法

[[ 屬性列表 ]] (C++11 起)
[[ using 屬性命名空間 : 屬性列表 ]] (C++17 起)

其中屬性列表 是由逗號分隔的零或更多個屬性 的序列(可以以指示包展開的省略號 ... 結束)

標識符
屬性命名空間 :: 標識符
標識符 ( 實參列表 (可選) )
屬性命名空間 :: 標識符 ( 實參列表 (可選) )

其中屬性命名空間為一個標識符,而實參列表為其中圓括號、方括號和花括號平衡出現的記號序列(平衡記號序列)。

1) 簡單屬性,例如 [[noreturn]]
2) 有命名空間的屬性,例如 [[gnu::unused]]
3) 有實參的屬性,例如 [[deprecated("原因")]]
4) 既有命名空間又有實參列表的屬性。

如果 using namespace: 出現在屬性列表開頭,那麼屬性列表中的其他屬性均無法指定命名空間:由 using 所指定的命名空間會應用到所有這些屬性:

[[using CC: opt(1), debug]] // 同 [[CC::opt(1), CC::debug]]
[[using CC: CC::opt(1)]] // 错误:不能结合 using 和有作用域属性
(C++17 起)

解釋

屬性為各種由實現定義的語言擴展(例如 GNU 與 IBM 的語言擴展 __attribute__((...)),微軟的語言擴展 __declspec() 等)提供了統一的語法。

屬性可用在 C++ 程序中的幾乎所有位置,而且可應用於幾乎所有事物:類型、變量、函數、名字、代碼塊、整個翻譯單元,不過每個特定的屬性都只在實現允許範圍內有效:[[expect_true]] 可能是只能與 if,而非與類聲明一同使用的屬性,[[omp::parallel()]] 可能是應用到代碼塊或 for 循環,而非到類型 int 等的屬性。(請注意以上兩個屬性只是虛構的例子,有關標準與一些非標準屬性請見下文。)

在聲明中,屬性既可以在整個聲明之前出現,也可以直接跟在被聲明實體的名字之後,這些情況下它們被組合起來。大多數其他情形中,屬性應用於直接位於其之前的實體。

雖然 alignas 說明符擁有不同的語法,但它是屬性序列說明符的一部分。它可以在 [[...]] 屬性出現的地方出現,並可以和它們混合(假設此處允許使用 alignas)。

兩個連續的方括號記號([[)只能出現於引入屬性說明符之處,或在屬性實參之內。

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

除了以下所列出的標準屬性之外,實現還可能支持擁有由實現定義的行為的任意非標準屬性。所有實現所未知的屬性均被忽略,且不產生錯誤。(C++17 起)

屬性命名空間 的屬性與名字以 stdstd 後隨一或多個數字的屬性命名空間 為未來標準化保留。即每個非標準屬性都在實現提供的 屬性命名空間 中,例如 [[gnu::may_alias]][[clang::trivial_abi]][[msvc::noop_dtor]]

(C++20 起)

標準屬性

C++ 標準定義了下列屬性。

標準屬性不能在語法上被忽略:它們不能包含語法錯誤,必須應用到正確的目標,並且實參中的實體都會被 ODR 使用

標準屬性也不能在語義上被忽略:程序在去掉某個標準屬性的所有實例的情況下的行為必須是該程序在保留該屬性的情況下遵守標準要求的行為。

(C++11)
指示函數不返回
(屬性指示符)
(C++11)(C++26 移除)
指示在函數內外傳播「釋放-消費」std::memory_order 中的依賴鏈
(屬性指示符)
[[deprecated]][[deprecated("原因")]]
(C++14)(C++14)
指示以此屬性聲明的名字或實體,允許使用但因某種原因 而不鼓勵使用
(屬性指示符)
(C++17)
指示從前一 case 標號的直落是故意的,且會警告直落的編譯器不應當對此診斷
(屬性指示符)
(C++17)
抑制對於未使用實體的編譯器警告,如果有
(屬性指示符)
[[nodiscard]][[nodiscard("原因")]]
(C++17)(C++20)
鼓勵編譯器在返回值被丟棄時發出警告
(屬性指示符)
(C++20)(C++20)
指示編譯器應當針對此種情況進行優化:通過某條語句的執行路徑比其他任何執行路徑更可能或不可能發生
(屬性指示符)
指示一個非靜態數據成員不必具有與類中的其他所有非靜態數據成員都不同的地址
(屬性指示符)
[[assume(表達式)]]
(C++23)
指示表達式 在給定的位置永遠為 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(); // 声明 f 带四个属性

[[gnu::always_inline, gnu::const, gnu::hot, nodiscard]]
int f(); // 同上,但使用含有四个属性的单个属性说明符

// C++17:
[[using gnu : const, always_inline, hot]] [[nodiscard]]
int f[[gnu::always_inline]](); // 属性可出现于多个说明符中

int f() { return 0; }

int main() {}

缺陷報告

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

缺陷報告 應用於 出版時的行為 正確行為
CWG 2079 C++11 [[ 不能在屬性實參之內出現 可以出現
CWG 2538 C++11 不明確標準屬性是否能在語法上被忽略 禁止忽略
CWG 2695 C++11 不明確標準屬性是否能在語義上被忽略 禁止忽略
P2156R1 C++11 每個標準屬性在一個屬性列表 中最多只能出現一次 不限制次數

參閱

__has_cpp_attribute - 檢查某個屬性是否存在
屬性說明符序列C 文檔

外部連結

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