如何优雅地检测类型/表达式有效性?
注1:本文至少需要編譯器支持C 11。
注2:本文不考慮使用宏。
一、老辦法
在寫C 的時候,有時候可能需要檢查一個類是否有特定的成員類型,例如:
// 檢查 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"); // 存在或者需要檢查一個類是否有特定的成員函數,例如:
如果是在很久以前的 C 98 時代,可能會這樣利用 SFINAE 實現:
如果 T::type 存在的話就會選擇第一個重載,否則就會選擇第二個重載,由此判斷 T::type 是否存在。但是這樣的代碼閱讀起來可能會挺費勁的……于是,現在有了 void_t!
二、void_t
void_t<...>?其實就是 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 才成為標準庫的一部分,但是我們可以在 C 11 中自己造一個:
template??struct?make_void?{?using?type?=?void;?};template??using?void_t?=?typename?make_void::type;需要注意的是上面的定義是為了兼容 C 11 / C 14 而這樣寫的,因為別名模板中未被使用的模板參數可能會被忽略。但如果是 C 17 的話,編譯器就不能忽略別名模板中未被使用的模板參數,就可以直接這樣寫:
(當然有 C 17 的話就能用標準庫的?std::void_t?了……)
同理,我們也可以用同樣的方式判斷成員函數是否存在:
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,但每次需要一個新的判定就得再擼一遍 SFINAE,依然有點不夠直觀(你說用宏?…… 我什么都沒聽到)。那么我們為什么不把這種判定也提煉成模板呢?有請 is_detected 出場——
template?using?has_type_t?=?typename?T::type;template?using?has_type?=?is_detected;看起來使用 is_detected 的方法比之前的 has_type 清爽多了吧,而且非常直觀。
雖然 is_detected 還沒有進入標準,但我們依然可以在 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;如果仔細看的話,你就能夠發現這就是給之前的方法加上了模板模板參數,使得它更容易使用。下面是用 is_detected 判斷成員函數是否存在:
當然,is_detected 還可以做到更多,只要你能夠寫出 Op 的話就有很多可以做的事情,比如說做各種 concept 的檢查。除了 is_detected 之外,Detection Idiom 還有 detected_t 和 detected_or 等工具,可以用于在 trait 中實現默認類型,這里就不再展開介紹,感興趣的話可以到上面的鏈接里看一下。
來源:https://zhuanlan.zhihu.com/p/2615546
總結
以上是生活随笔為你收集整理的如何优雅地检测类型/表达式有效性?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux工程师证书(linux认证工程
- 下一篇: linux删除非空目录的命令(linux