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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

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

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

注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ù),例如:

// 檢查 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 時(shí)代,可能會(huì)這樣利用 SFINAE 實(shí)現(xiàn):

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 存在的話就會(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ù),就可以直接這樣寫:

template?using?void_t?=?void;

(當(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ù)是否存在:

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

當(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)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。