我有以下代碼:
int add_ii(int a, int b) { return a b; }
unsigned add_iu(int a, unsigned b) { return a b; }
unsigned add_ui(unsigned a, int b) { return a b; }
unsigned add_uu(unsigned a, unsigned b) { return a b; }
#define add(LEFT, RIGHT) \
_Generic(LEFT \
,int: _Generic(RIGHT \
,int: add_ii \
,unsigned: add_iu \
) \
,unsigned: _Generic(RIGHT \
,int: add_ui \
,unsigned: add_uu \
) \
)(LEFT, RIGHT)
int main() {
return add(1, add(2, add(3, 4)));
}
問題是RIGHT針對每種_Generic情況進行了擴展。在上面,RIGHT使用了3次,所以add(2, add(3, 4))完全展開了3次,所以add(3, 4)展開了9次。這個數字隨著每次嵌套使用和內部處理的每個附加型別呈指數增長_Generic。這本身不是問題 - 但它會導致前處理器生成非常大的輸出,這會顯著拖延編譯程序并導致非常高的編譯記憶體使用率。
有什么方法可以撰寫二維,_Generic以便RIGHT每次都不會針對每種型別進行擴展?
開關LEFT與RIGHT當然不是一種選擇,并不會做太多-LEFT將隨后擴大了許多倍。
我知道我可以使用 GNU 擴展,但我的想法是我不想使用它們:
#define add(LEFT, RIGHT0) ({
__auto_type LEFT = LEFT0;
__auto_type RIGHT = RIGHT0;
_Generic(LEFT, .....)(LEFT, RIGHT)
})
我可以寫一種映射,但這會擦除回傳型別資訊并要求將所有函式型別強制轉換為通用型別,或者使用一些不安全的va_arg:
unsigned add_ii_adaptor(unsigned a, unsigned b) { return add_ii(a, b); }
unsigned add_iu_adaptor(unsigned a, unsigned b) { return add_iu(a, b); }
unsigned add_ui_adaptor(unsigned a, unsigned b) { return add_ui(a, b); }
static unsigned (*const funcarr[])(unsigned a, unsigned b) = {
add_ii_adaptor,
add_iu_adaptor,
add_ui_adaptor,
add_uu,
};
#define typeidx(x) _Generic((x), int: 0, unsigned 1)
#define add(LEFT, RIGHT) \
funcarr[typeidx(LEFT) << 1 | typeidx(RIGHT)](LEFT, RIGHT)
有沒有我忽略的方法?
背景:However, what is the ultimate point here?我執行整數安全n2792沒有GNU擴展這里。我想支持 26 種型別,ckd_add(x, y, z)使其成為 17576 種型別的組合。(這可以減少,但仍然如此)。在上面的例子中,回傳型別是運算元的提升型別,所以unsigned int = unsigned,但例如它可能是long char = long *or unsigned long!*。
uj5u.com熱心網友回復:
可以用于_Generic將元組映射到整數。您需要一個由整數引數化的型別,而 C 提供了這樣一個系列...陣列。但是,陣列不能用作分派引數,因為陣列會衰減為指標。但是,指向陣列的指標不會衰減。
只需使用typeidx-like 宏計算陣列的大小,并將其用作新陣列型別的大小。添加1是因為 C 禁止零大小陣列。
接下來使用復合文字形成指向它的指標。式(int(*)[3]) { 0 }。最后,使用此文字的型別來調度適當的函式指標。
#define TYPE_TO_NUM(X) _Generic((X), int: 0, unsigned: 1)
#define add(LEFT, RIGHT) \
_Generic( \
(int(*)[1 2 * TYPE_TO_NUM(LEFT) TYPE_TO_NUM(RIGHT)]) { 0 } \
,int(*)[1]: add_ii \
,int(*)[2]: add_iu \
,int(*)[3]: add_ui \
,int(*)[4]: add_uu \
)(LEFT, RIGHT)
由于擴展LEFT和RIGHT兩倍,該解決方案仍然具有指數復雜性,但比原始解決方案快得多。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/366644.html
