泛型選擇 (自 C11 起)
提供一種在編譯時期,根據控制表達式的類型來選擇多個表達式之一的方法。
目錄 |
[編輯] 語法
_Generic ( 控制表達式 (controlling-expression) , 關聯列表 (association-list) ) |
(自 C11 起) | ||||||||
其中 關聯列表 是以逗號分隔的關聯清單,每一個關聯的語法如下:
類型名稱 (type-name) : 表達式 (expression) |
|||||||||
default : 表達式 (expression) |
|||||||||
其中
| 類型名稱 | - | 任何非變長(variably-modified)的完整 物件類型(即不是 VLA 或 VLA 指標)。 |
| 控制表達式 | - | 任何表達式(逗號運算子除外),若未使用 default 關聯,則其類型必須與其中一個 類型名稱 相容。 |
| expression | - | 任何類型和值類別的任意表達式(逗號運算子除外)。 |
關聯列表 中的任意兩個 類型名稱 不得指定 相容類型。每個關聯列表只能有一個使用 default 關鍵字的關聯。如果未使用 default 且沒有任何一個 類型名稱 與控制表達式的類型相容,則程式無法編譯。
[編輯] 解釋
首先,控制表達式 的類型會進行 左值轉換 (lvalue conversions)。此轉換僅在類型域中執行:它會捨棄頂層的 cvr-限定符 (cvr-qualifiers) 與原子性 (atomicity),並將陣列轉指標/函數轉指標的變換應用於控制表達式的類型,過程中不會觸發任何副作用或計算任何數值。
轉換後的類型會與關聯列表中的 類型名稱 進行比較。
若該類型與其中一個關聯的 類型名稱 相容,則該泛型選擇的類型、值和 值類別 (value category) 即為該 類型名稱 後冒號所對應的 表達式 之類型、值和值類別。
若沒有任何 類型名稱 與 控制表達式 的類型相容,且提供了 default 關聯,則泛型選擇的類型、值和值類別為 default : 標籤後方表達式之類型、值和值類別。
[編輯] 備註
控制表達式 以及未被選中的選擇項之 表達式 均不會被求值。
由於進行了左值轉換,"abc" 會匹配 char* 而非 char[4],且 (int const){0} 會匹配 int,而非 const int。
所有 值類別(包括函數指示符與 void 表達式)均可作為泛型選擇中的 表達式;若被選中,該泛型選擇本身將具有相同的值類別。
C99 引入的 類型泛型數學巨集(來自 <tgmath.h>)是以編譯器特定的方式實作的。而 C11 引入的泛型選擇,讓開發者能夠編寫類似的類型依賴代碼。
泛型選擇類似於 C++ 中的重載(在編譯時期根據參數類型選擇多個函數之一),差異在於它是針對任意表達式進行選擇。
[編輯] 關鍵字
[編輯] 範例
#include <math.h> #include <stdio.h> // Possible implementation of the tgmath.h macro cbrt #define cbrt(X) _Generic((X), \ long double: cbrtl, \ default: cbrt, \ float: cbrtf \ )(X) int main(void) { double x = 8.0; const float y = 3.375; printf("cbrt(8.0) = %f\n", cbrt(x)); // selects the default cbrt printf("cbrtf(3.375) = %f\n", cbrt(y)); // converts const float to float, // then selects cbrtf }
輸出
cbrt(8.0) = 2.000000 cbrtf(3.375) = 1.500000
[編輯] 缺陷報告
以下變更行為的缺陷報告已回溯應用於先前發佈的 C 標準。
| DR | 應用於 | 出版時的行為 | 正確的行為 |
|---|---|---|---|
| DR 481 | C11 | 對於控制表達式是否進行左值轉換的規定不明確 | 已明確規定會進行轉換 |
[編輯] 參考資料
- C23 標準 (ISO/IEC 9899:2024)
- 6.5.1.1 泛型選擇 (p: 待定)
- C17 標準 (ISO/IEC 9899:2018)
- 6.5.1.1 泛型選擇 (p: 56-57)
- C11 標準 (ISO/IEC 9899:2011)
- 6.5.1.1 泛型選擇 (p: 78-79)
[編輯] 參閱
| C++ 文件 關於 模板 (Templates)
|