跳至內容

C++/特性

維基教科書,自由的教學讀本
< C++

從C++11開始,引入了特性(attribute)概念,用於編譯器實現定義的類型、對象、代碼等的特性。編譯器可在特定於該編譯器的命名空間中定義其自己的特性;但編譯器只需識別標準中定義的特性。編譯器忽略它們無法識別的特性值。

    attr attr1, attr2, attr3(args) namespace::attr(args) alignas_specifier 

形式上的語法為:

attribute-list  		(从 C++11)
using attribute-namespace : attribute-list  		(从 C++17)

其中attribute-list是逗號分隔的序列,包含0個或多個特性,可以以省略號...結尾表示包展開(pack expansion)

特性可以為:

identifier 		例如noreturn
attribute-namespace :: identifier 	例如gnu::unused	
identifier ( argument-list ) 		例如deprecated("because")
attribute-namespace :: identifier ( argument-list ) 		

C++17開始,使用特性列表的開始處加上「using: namespace」,那麼特性列表中其他的特性就不能再指定命名空間:using指定的命名空間被應用於所有特性上。例如:

using CC: opt(1), debug // 等效于 CC::opt(1), CC::debug
using CC: CC::opt(1) // 出错:不能组合使用using与作用域限定的特性

解釋

[編輯]

特性提供了統一的標準語法用於編譯器實現相關的語言擴展,如GNU語言擴展__attribute__((...)),Microsoft擴展__declspec()等等。

特性可用於C++程序的各處,也適用於各個要素:類型、變量、函數、名字、代碼塊、整個編譯單元,雖然每個特定特性僅適用於實現允許的地方,如expect_true只能用於if,不能用於類的聲明。omp::parallel()可用於代碼塊或for循環,但不能用於int類型。

標準特性

[編輯]
  • noreturn 函數沒有return。換句話說,函數總是拋出異常。一個函數如果有該特性,它在各個編譯單元的第一次聲明時都要指出該特性
  • carries_dependency indicates that dependency chain in release-consume std::memory_order propagates in and out of the function
  • deprecated(C++14)
  • deprecated("reason")(C++14) 允許使用,但是不鼓勵
  • fallthrough(C++17) 從前一個case標籤的直落(fall through)是故意的,編譯器不應該診斷為直落警告
  • nodiscard(C++17)
  • nodiscard("reason")(C++20) 鼓勵編譯器發出一個警告,如果返回值被丟棄
  • maybe_unused(C++17) 對可能未被使用的實體,抑制編譯器警告
  • likely(C++20)
  • unlikely(C++20) 讓編譯器優化這種情形,該執行路徑的語句比其他執行路徑可能性更大或更小。
  • no_unique_address(C++20) 指出一個非靜態數據成員可能與這個類的其他非靜態數據成員有相同地址
  • optimize_for_synchronized(TM TS) 指出函數定義可以優化以被同步調用

例子

[編輯]
[[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()
{
}