91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C++中怎么定義type_traits

發布時間:2022-08-15 16:15:12 來源:億速云 閱讀:178 作者:iii 欄目:開發技術

這篇文章主要介紹“C++中怎么定義type_traits”,在日常操作中,相信很多人在C++中怎么定義type_traits問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”C++中怎么定義type_traits”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

模板編程不像常規的代碼,可以有if-else這些流控制語句,我們需要充分利用模板、模板特例、類型轉換等特性來實現編譯期的一系列判斷和類型轉換。

定義基礎常量

第一步,我們需要定義true和false兩個常量,所有的type_traits都基于此。我們的目的就是要用一個模板類型來表示是非,其中的value正好是這兩個值。之后我們更高級的判斷類型都是繼承自這兩個類型的其中一個,通過這種方式獲取value值就可以獲取true和false了。

如果聽這個解釋有點暈的話,不要緊,我們直接來看代碼。這里需要注意的是,既然type_traits都是編譯期行為,因此其成員只能是靜態不可變成員(編譯期就可以確定的成員)。

struct true_type {
    static constexpr bool value = true;
};
struct false_type {
    static constexpr bool value = false;
};

基礎類型判斷

有了基礎常量,我們可以先做一些簡單的類型判斷,比如說判斷這個類型是不是void。這里的思路是,針對于所有類型的模板,繼承自false_type,而針對于void類型,我們給予一個模板特例,讓他繼承自true_type。這樣一來,只有當類型是void的時候才會推導true,其他的就會推導false。請看例程:

template <typename>
struct is_void : false_type {};
template <>
struct is_void<void> : true_type {};

這里我們可以做一些簡單的測試,來判斷函數的返回值是否為void:

void test1();
int test2();
int main(int argc, const char *argv[]) {
    std::cout << is_void<decltype(test1())>::value << std::endl; // 1
    std::cout << is_void<decltype(test2())>::value << std::endl; // 0
    return 0;
}

有了判斷void的思路基礎,不難寫出判斷其他類型的,比如說判斷是否為浮點數,那么只需要對float,double,long double進行特殊處理即可,請看代碼:

template <typename>
struct is_floating_point : false_type {};
template <>
struct is_floating_point<float> : true_type {};
template <>
struct is_floating_point<double> : true_type {};
template <>
struct is_floating_point<long double> : true_type {};

整型判斷相對復雜一點,需要對char,signed char,unsigned char,short,unsigned short,int,unsigned,long,unsigned long,long long,unsigned long long都進行特例編寫,方法相同,不再贅述。

類型處理

在上一節編寫is_floating_point的時候可能會發現這樣的問題:

int main(int argc, const char *argv[]) {
    std::cout << is_floating_point<const double>::value << std::endl; // 0
    std::cout << is_floating_point<double &>::value << std::endl; // 0
    return 0;
}

但是照理來說,const類型以及引用類型不應該影響他浮點數的本質,當然,我們也可以針對所有的const以及引用情況都編寫模板特例,但這樣太麻煩了,如果有辦法可以去掉const以及引用這些符號,然后再去判斷的話,就會減少我們很多工作量。與此同時,這樣的類型處理在實際編程時也是很有用的。

那么,如何去掉const?請看代碼:

template <typename T>
struct remove_const {
    using type = T;
};
template <typename T>
struct remove_const<const T> {
    using type = T;
};

同樣的思路,當T是const類型時,我們變換成const T,然后只取出T,其他類型時直接透傳T。

同理,用這種方法也可以去除引用:

template <typename T>
struct remove_reference {
    using type = T;
};
template <typename T>
struct remove_reference<T &> {
    using type = T;
};
template <typename T>
struct remove_reference<T &&> {
    using type = T;
};

因此,is_floating_point就可以改寫成這樣:

// 基礎判斷降級為helper
template <typename>
struct is_floating_point_helper : false_type {};
template <>
struct is_floating_point_helper<float> : true_type {};
template <>
struct is_floating_point_helper<double> : true_type {};
template <>
struct is_floating_point_helper<long double> : true_type {};
// remove_reference和remove_const的聲明
template <typename>
struct remove_const;
template <typename>
struct remove_reference;
// 實際的is_floating_point
template <typename T>
struct is_floating_point : is_floating_point_helper<typename remove_const<typename remove_reference<T>::type>::type> {};

類型選擇

我們搞這樣一系列的類型封裝,最主要的原因是為了在編譯器進行邏輯判斷。因此,必然要進行一個選擇邏輯,也就是當條件成立時,選擇某一個類型,不成立時選擇另一個類型。這個功能非常好實現,請看代碼:

template <bool judge, typename T1, typename T2>
struct conditional {
    using type = T1;
};
template <typename T1, typename T2>
struct conditional<false, T1, T2> {
    using type = T2;
};

當第一個參數為true時,type就與T1相同,否則就與T2相同。

判斷是否相同

我們有時候還需要判斷兩個類型是否相同,這部分也很好實現,請看代碼:

template <typename, typename>
struct is_same : false_type {};
template <typename T>
struct is_same<T, T> : true_type {};

tips

其實按照這些邏輯,我們幾乎可以寫出type_traits中的所有功能了。STL中還實現了合取、析取、取反等操作,只是將邏輯判斷轉為了模板形式,這些用起來更方便,但不是必須的。大家感興趣可以閱讀這部分源碼。

實現is_base_of

is_base_of用于判斷兩個類型是否是繼承關系,在C++中已經存在了對應的關鍵字用于判斷:

struct B {};
struct D : B {};
struct A {};
int main(int argc, const char *argv[]) {
    std::cout << __is_base_of(B, D) << std::endl; // 1
    std::cout << __is_base_of(B, A) << std::endl; // 0
    return 0;
}

__is_base_of關鍵字就可以完成這樣的工作,所以我們封裝它為模板即可:

template <typename B, typename D>
struct is_base_of : conditional<__is_base_of(B, D), true_type, false_type> {};

但除了這種直接使用編譯器提供的關鍵字外,這個功能還有一種其他的實現方法。

如何判斷一個類是否為一個類的父類呢?其實就看指針能否轉換(多態)即可。請看代碼:

template <typename B, typename D>
true_type test_is_base(B *);
template <typename B, typename D>
false_type test_is_base(void *);
template <typename B, typename D>
struct is_base_of : decltype(test_is_base<B, D>(static_cast<D *>(nullptr))) {};

如果D是B的子類,那么就會調用第一個函數,從而推斷出返回值是true_type,否則調用第二個函數,推斷出返回值是false_type。

不過這樣做還必須加一個判斷,就是B和D必須都是類才行,而且需要去掉const等因素。

到此,關于“C++中怎么定義type_traits”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

c++
AI

肇州县| 家居| 泽普县| 昌乐县| 石泉县| 西吉县| 广西| 九龙县| 新郑市| 正镶白旗| 闽侯县| 玛纳斯县| 兴山县| 英吉沙县| 穆棱市| 监利县| 平定县| 漯河市| 荣昌县| 于田县| 屏边| 长汀县| 泌阳县| 永仁县| 墨脱县| 黑山县| 凌源市| 永清县| 高邮市| 武强县| 乐都县| 灵山县| 霞浦县| 宝清县| 迭部县| 来宾市| 集安市| 玉门市| 无棣县| 平泉县| 崇左市|