啃模板技術之SFINAE

2021-08-21 03:48:19 字數 1449 閱讀 7500

sfinae說直白點就是模板類和模板函式匹配替換,找候選時的取捨過程。模板的篩選確定一定是要找到最準確的那個,而恰恰c++又支援類模板的特化和函式過載,那面對多個同名的定義,怎麼辦?先找出所有候選,候選的意思是能用就用,不能用換別個。所以對挑選過程一視同仁,先做實參的型別替換,乙個不匹配就換下乙個。這個合不合適本質上就是條件判斷,既然編譯器能做判斷,那來嘛,我給你幾個同名符號你給判斷一下,這個判斷題有點埋坑的意思,表面是做同名符號的篩選,其實另有目的,比如試探下有沒有某個成員、是不是某個型別等,都是判斷題。有點欺負老實人的意思,就好比你想知道的答案不太好直接問,於是換了另乙個相對容易接受的問題。道理講清楚了,就看會不會埋坑(trap)了。

1. 使用sfinae技術判斷乙個類是否無析構函式

//1. 基於成員函式模板的實現

templatestruct has_no_destroy

;//2. 基於類特化的實現

template struct has_destory : std::false_type{};

template struct has_destory> : std::true_type{};

template constexpr bool has_destroy_v = has_destory::value;

如果測試型別中存在no_destroy靜態函式,則在模板匹配時,匹配返回值為char型別的函式,否則匹配可變引數、返回值為int32_t的函式。所以根據返回值型別的不同確定其實際匹配的函式版本。

對於基於類特化的版本,has_destroy_v 對類模板例項化時僅指定了乙個模板實參,所以第二個引數一定會使用類模板中指定的預設引數,所以在型別替換的時候,若主模板的預設引數本身就不合法則直接報編譯錯誤。因此,若要基於類特化的實現,則一定要保證主模板的預設值是能夠正確替換的。這也是為什麼要將「試探表示式」-decltype(&t::no_destory)放在特化版本中的原因。

2. 模板函式的顯式例項化(explicit instantiation)和顯式特化(explicit specialization)

對函式而言,存在顯式例項化和顯式例項化的差別,如下所示:

//普通模板定義

template void convert(t v)

//顯式模板例項化

template void convert(double)

//引數可推導,則可省略

template void convert(double);

//模板顯式特化

template<>

void convert(int v)

通常模板採用隱式例項化方式,即在使用模板函式時,例項化型別引數對應的模板。如果強制生成對應型別的例項化,則需要顯式例項化。在模板匹配時,其優先順序順序為:

普通函式》顯式特化》顯式具體化》普通模板函式

C 模板之SFINAE技術

templatestruct has no destroy 有乙個模板類的成員函式呼叫了它 static void init 看起來很不明白為什麼。然後蒐集資料,學習到了c 模板除了萃取的又乙個新技術,sfinae技術,即匹配失敗不是錯誤。sfinae的意思是這樣的,假如有乙個特化會導致編譯時錯誤 ...

模板之組合技術

1 模板可以遞迴呼叫 listli list lli list llli 2 如果需要特定的 組合型別 可以通過派生來定義它們。這是派生的一種不太常見的應用,因為這裡並不增加成員。這種派生的應用也不會造成任何時間或則空間上的開銷 template class list2 public list li...

jQuery慢慢啃之特效(八)

1.show speed,easing fn 顯示隱藏的匹配元素 speed 三種預定速度之一的字串 slow normal or fast 或表示動畫時長的毫秒數值 如 1000 easing optional 用來指定切換效果,預設是 swing 可用引數 linear p show p sho...