命名空間
變體
動作

泛型選擇 (自 C11 起)

出自 cppreference.com
< c‎ | 語言

提供一種在編譯時期,根據控制表達式的類型來選擇多個表達式之一的方法。

目錄

[編輯] 語法

_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++ 中的重載(在編譯時期根據參數類型選擇多個函數之一),差異在於它是針對任意表達式進行選擇。

[編輯] 關鍵字

_Generic, default

[編輯] 範例

#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)
English Deutsch 日本語 中文(简体) 中文(繁體)