日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

如何优雅地检测类型/表达式有效性?

發布時間:2023/12/2 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何优雅地检测类型/表达式有效性? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

注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"); // 存在

或者需要檢查一個類是否有特定的成員函數,例如:

// 檢查 T.get() 是否存在,存在則 value 為 true,否則為 falsetemplate <typename T>struct has_get; struct A {};struct B { int get() { return 42; } };static_assert(!has_get::value, "Failed"); // 不存在static_assert(has_get::value, "Failed"); // 存在

如果是在很久以前的 C 98 時代,可能會這樣利用 SFINAE 實現:

template?struct?has_type?{private:????typedef?char?one;????typedef?struct?{?char?data[2];?}?two;????//?存在的話返回類型為?one????template??static?one?test(typename?U::type*);????//?不存在的話返回類型為?two????template??static?two?test(...);public:????enum?{?value?=?sizeof(test(0))?==?sizeof(one)?};};

如果 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 的話,編譯器就不能忽略別名模板中未被使用的模板參數,就可以直接這樣寫:

template?using?void_t?=?void;

(當然有 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 判斷成員函數是否存在:

template?using?has_get_t?=?decltype(std::declval().get());template?using?has_get?=?is_detected;

當然,is_detected 還可以做到更多,只要你能夠寫出 Op 的話就有很多可以做的事情,比如說做各種 concept 的檢查。除了 is_detected 之外,Detection Idiom 還有 detected_t 和 detected_or 等工具,可以用于在 trait 中實現默認類型,這里就不再展開介紹,感興趣的話可以到上面的鏈接里看一下。

來源:https://zhuanlan.zhihu.com/p/2615546

總結

以上是生活随笔為你收集整理的如何优雅地检测类型/表达式有效性?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。