如何优雅地检测类型/表达式有效性?
注1:本文至少需要編譯器支持C 11。
注2:本文不考慮使用宏。
一、老辦法
在寫C 的時(shí)候,有時(shí)候可能需要檢查一個(gè)類是否有特定的成員類型,例如:
// 檢查 T::type 是否存在,存在則 value 為 true,否則為 falsetemplate <typename T>struct has_type; struct A {};struct B { using type = int; };static_assert(!has_type::value, "Failed"); // 不存在static_assert(has_type::value, "Failed"); // 存在或者需要檢查一個(gè)類是否有特定的成員函數(shù),例如:
如果是在很久以前的 C 98 時(shí)代,可能會(huì)這樣利用 SFINAE 實(shí)現(xiàn):
如果 T::type 存在的話就會(huì)選擇第一個(gè)重載,否則就會(huì)選擇第二個(gè)重載,由此判斷 T::type 是否存在。但是這樣的代碼閱讀起來可能會(huì)挺費(fèi)勁的……于是,現(xiàn)在有了 void_t!
二、void_t
void_t<...>?其實(shí)就是 void,但它可以在 SFINAE 中幫助判斷類型是否存在,示例如下:
template?<typename?T,?typename?=?void>struct?has_type?:?std::false_type?{};template?struct?has_type<T,?void_t>?:?std::true_type?{};(看起來是不是和 enable_if 的某種用法有相似之處?)
雖然 void_t 在 C 17 才成為標(biāo)準(zhǔn)庫(kù)的一部分,但是我們可以在 C 11 中自己造一個(gè):
template??struct?make_void?{?using?type?=?void;?};template??using?void_t?=?typename?make_void::type;需要注意的是上面的定義是為了兼容 C 11 / C 14 而這樣寫的,因?yàn)閯e名模板中未被使用的模板參數(shù)可能會(huì)被忽略。但如果是 C 17 的話,編譯器就不能忽略別名模板中未被使用的模板參數(shù),就可以直接這樣寫:
(當(dāng)然有 C 17 的話就能用標(biāo)準(zhǔn)庫(kù)的?std::void_t?了……)
同理,我們也可以用同樣的方式判斷成員函數(shù)是否存在:
template?<typename?T,?typename?=?void>struct?has_get?:?std::false_type?{};template?struct?has_get<T,?void_t<decltype(std::declval().get())>>?:?std::true_type?{};三、Detection Idiom:is_detected
即使我們有了 void_t,但每次需要一個(gè)新的判定就得再擼一遍 SFINAE,依然有點(diǎn)不夠直觀(你說用宏?…… 我什么都沒聽到)。那么我們?yōu)槭裁床话堰@種判定也提煉成模板呢?有請(qǐng) is_detected 出場(chǎng)——
template?using?has_type_t?=?typename?T::type;template?using?has_type?=?is_detected;看起來使用 is_detected 的方法比之前的 has_type 清爽多了吧,而且非常直觀。
雖然 is_detected 還沒有進(jìn)入標(biāo)準(zhǔn),但我們依然可以在 C 11 中把它造出來:
template <typename, template <typename...> class Op, typename... T>struct is_detected_impl : std::false_type {};template <template <typename...> class Op, typename... T>struct is_detected_impl<void_t<Op>, Op, T...> : std::true_type {}; template <template <typename...> class Op, typename... T>using is_detected = is_detected_impl;如果仔細(xì)看的話,你就能夠發(fā)現(xiàn)這就是給之前的方法加上了模板模板參數(shù),使得它更容易使用。下面是用 is_detected 判斷成員函數(shù)是否存在:
當(dāng)然,is_detected 還可以做到更多,只要你能夠?qū)懗?Op 的話就有很多可以做的事情,比如說做各種 concept 的檢查。除了 is_detected 之外,Detection Idiom 還有 detected_t 和 detected_or 等工具,可以用于在 trait 中實(shí)現(xiàn)默認(rèn)類型,這里就不再展開介紹,感興趣的話可以到上面的鏈接里看一下。
來源:https://zhuanlan.zhihu.com/p/2615546
總結(jié)
以上是生活随笔為你收集整理的如何优雅地检测类型/表达式有效性?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux工程师证书(linux认证工程
- 下一篇: C 条件变量使用详解