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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

还搞不懂STL的type_traits?从源码来带你一起分析

發布時間:2024/4/11 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 还搞不懂STL的type_traits?从源码来带你一起分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 什么是類型萃取?
  • 源碼剖析
    • SGI-STL G2.9版本類型萃取
    • C++標準庫類型萃取
      • SFINAE機制與enable_if
      • conditional
      • 核心結構:integral_constant 與bool_constant
      • is_same
      • 類型轉換:remove/add_xx()
      • 實戰分析:is_void


什么是類型萃取?

type_traits被稱為類型萃取,主要用于在編譯期計算、查詢、判斷、轉換和選擇,增強了泛型編程的能力,也增強了程序的彈性,使得我們在編譯期就能做到優化改進甚至排錯,能進一步提高代碼質量。

cplusplus-type_traits
在C++中類型萃取主要包含三大部分

  • 輔助類(Helper classes)

    • 用于幫助創建編譯器常量的標準類。
  • 類型萃取(Type traits)

    • 在編譯期以常量的形式獲取類的特征。
  • 類型轉換(Type transformations)

    • 為某個類型增加/刪除屬性。例如增加/刪除const、volatile等。


源碼剖析

以下代碼全部來自C++標準庫的type_traits、xtr1common,SGI-STL的type_traits.h文件中,為了方便閱讀與理解,在一些重要的地方我會加上注釋。

SGI-STL G2.9版本類型萃取

考慮到理解難度,我們先不講標準庫的類型萃取,先看看G2.9的STL中單獨封裝的類型萃取。

在SGI-STL的類型萃取中,每個類型其主要關注六個參數

  • this_dummy_member_must_be_first:這個虛函數成員必須為第一個參數
  • has_trivial_default_constructor:默認的構造函數是否不重要。
  • has_trivial_copy_constructor:拷貝構造函數是否不重要。
  • has_trivial_assignment_operator:賦值運算符是否不重要。
  • has_trivial_destructor:析構函數是否不重要。
  • is_POD_type:是否為基本類型。

為什么要選擇這些參數呢?例如我們在使用一個容器時(例如vector<type>),如果其為自定義類型,我們需要在構造的時候為每一個成員調用一次構造函數,在析構的時候調用一次析構函數。但是對于內置類型來說,這些操作完全不必要,我們可以直接采用內存直接處理操作如malloc()、memcpy()等方法來以最高效率執行。

如果我們準備對一個類型未知的數組進行拷貝操作時,如果能夠提前知道它使用的是默認的拷貝構造函數,就可以直接使用memcpy、memmove來快速進行拷貝,對于STL中這些大規模且操作頻繁的容器,帶來了巨大的性能提升。

下面結合源碼,來看看它們是怎么實現的

struct __true_type { };struct __false_type { };//泛化模板 template <class type> struct __type_traits { typedef __true_type this_dummy_member_must_be_first;typedef __false_type has_trivial_default_constructor;typedef __false_type has_trivial_copy_constructor;typedef __false_type has_trivial_assignment_operator;typedef __false_type has_trivial_destructor;typedef __false_type is_POD_type; };//特化,太多了這里只舉幾個例子 __STL_TEMPLATE_NULL struct __type_traits<char> {typedef __true_type has_trivial_default_constructor;typedef __true_type has_trivial_copy_constructor;typedef __true_type has_trivial_assignment_operator;typedef __true_type has_trivial_destructor;typedef __true_type is_POD_type; };__STL_TEMPLATE_NULL struct __type_traits<int> {typedef __true_type has_trivial_default_constructor;typedef __true_type has_trivial_copy_constructor;typedef __true_type has_trivial_assignment_operator;typedef __true_type has_trivial_destructor;typedef __true_type is_POD_type; };

STL中的做法十分簡單,其通過模板的特化來實現這個功能。對于泛化類型,它默認它的這些參數都是false的,而后再對所有的內置類型進行特化,將它們typedef為true,簡單高效的完成了這個功能。

C++標準庫類型萃取

C++標準庫中的類型萃取功能更加強大,但是實現也更加的復雜

SFINAE機制與enable_if

SFINAE(Substitution Failure is Not An Error)是C++ 的一種語言屬性,它的核心就是從一組重載函數中刪除模板實例化無效的函數——在編譯期編譯時,會將函數模板的形參替換為實參,如果替換失敗編譯器不會當作是個錯誤,直到找到那個最合適的特化版本,如果所有的模板版本都替換失敗那編譯器就會報錯。

這里用enable_if來舉個例子

template <bool _Test, class _Ty = void> struct enable_if {}; template <class _Ty> struct enable_if<true, _Ty> using type = _Ty; };template <bool _Test, class _Ty = void> using enable_if_t = typename enable_if<_Test, _Ty>::type;

從源碼我們可以看到,只有當第一個模板參數為true的時候,由于偏特化,其能夠匹配到第二個模板,此時的type才是有效的。而對于其他情況來說,編譯器都會直接忽略,直到匹配所有模板都失敗后,此時編譯器才會進行報錯。

通過SFINAE技術可以完成很多有趣的事,比如根據參數類型做不同的定制化操作。

conditional

為了能利用模板來實現如or、and等邏輯判斷,type_traits還實現了條件模板conditional

template <bool _Test, class _Ty1, class _Ty2> struct conditional { // Choose _Ty1 if _Test is true, and _Ty2 otherwiseusing type = _Ty1; };template <class _Ty1, class _Ty2> struct conditional<false, _Ty1, _Ty2> {using type = _Ty2; };template <bool _Test, class _Ty1, class _Ty2> using conditional_t = typename conditional<_Test, _Ty1, _Ty2>::type;

其泛化時默認type為第二個參數,而對于第一個參數為false的特化版本,則會使用第二個參數。

核心結構:integral_constant 與bool_constant

type_traits最核心的結構就是integral_constant與bool_constant,下面給出了它們的源代碼

integral_constant是類型萃取最底層的結構,其借助模板使我們能夠獲取到KEY與VALUE的值與類型。同時,integral_constant重載了類型轉換操作符與()操作符,使其能夠像一個函數一樣進行調用。

template <class _Ty, _Ty _Val> struct integral_constant {static constexpr _Ty value = _Val;using value_type = _Ty;using type = integral_constant; //類型轉換運算符重載,將對象轉換為value_type時隱式調用constexpr operator value_type() const noexcept {return value;}//()運算符重載,用于實現仿函數_NODISCARD constexpr value_type operator()() const noexcept {return value;} };

接著我們來分析bool_constant,其實它就是利用模板來對integral_constant進行了一層封裝。它用來檢查模板類型是否為某種類型,通過bool_constant我們可以獲取編譯期檢查的bool值結果。

template <bool _Val> using bool_constant = integral_constant<bool, _Val>;using true_type = bool_constant<true>; using false_type = bool_constant<false>;


is_same

接下來我們看看is_same這個類,下面給出源碼:

template <class _Ty1, class _Ty2> struct is_same : bool_constant<is_same_v<_Ty1, _Ty2>> {};

如果只從調用關系看,我們很容易將其看成一個函數,但是實際上它其實繼承于bool_constant,是一個仿函數對象。

它的主要作用是判斷兩個對象的類型是否相同,從源碼我們可以看出,這里主要依賴了is_same_v這個模板變量。

//借助模板的匹配規則判斷是否屬于相同類型 template <class, class> _INLINE_VAR constexpr bool is_same_v = false;template <class _Ty> _INLINE_VAR constexpr bool is_same_v<_Ty, _Ty> = true;

is_same_v借助模板的隱式匹配規則,來判斷兩個參數是否屬于同一個類型,只有兩個模板參數的類型都相同時,才為true。

類型轉換:remove/add_xx()

在類型萃取的時候,為了排除不必要的干擾,我們通常會對數據的原類型進行一些處理,比如去掉const、volatile、右值引用等屬性。

下面我們來看看比較常用的remove_const和remove_volatile的源碼:

//去除頂層const template <class _Ty> struct remove_const { using type = _Ty; };template <class _Ty> struct remove_const<const _Ty> {using type = _Ty; };template <class _Ty> using remove_const_t = typename remove_const<_Ty>::type;// 去除頂層volatile template <class _Ty> struct remove_volatile { using type = _Ty; };template <class _Ty> struct remove_volatile<volatile _Ty> {using type = _Ty; };template <class _Ty> using remove_volatile_t = typename remove_volatile<_Ty>::type;

它們的實現思路相同,都是利用了模板的偏特化來完成類型的消除,當我們的參數匹配到特化版本時,就會通過using關鍵字將type指定為泛化版本,完成消除。

通常,這兩個仿函數會搭配使用,因此標準庫又封裝它們再次成remove_cv

// STRUCT TEMPLATE remove_cv template <class _Ty> struct remove_cv { // remove top-level const and volatile qualifiersusing type = _Ty;template <template <class> class _Fn>using _Apply = _Fn<_Ty>; // apply cv-qualifiers from the class template argument to _Fn<_Ty> };template <class _Ty> struct remove_cv<const _Ty> {using type = _Ty;template <template <class> class _Fn>using _Apply = const _Fn<_Ty>; };template <class _Ty> struct remove_cv<volatile _Ty> {using type = _Ty;template <template <class> class _Fn>using _Apply = volatile _Fn<_Ty>; };template <class _Ty> struct remove_cv<const volatile _Ty> {using type = _Ty;template <template <class> class _Fn>using _Apply = const volatile _Fn<_Ty>; };template <class _Ty> using remove_cv_t = typename remove_cv<_Ty>::type;


實戰分析:is_void

上面講了一些類型萃取的關鍵函數,下面就來實際看一看它們到底是怎么運作的,首先選取最簡單的is_void來分析。

// STRUCT TEMPLATE is_void template <class _Ty> _INLINE_VAR constexpr bool is_void_v = is_same_v<remove_cv_t<_Ty>, void>;template <class _Ty> struct is_void : bool_constant<is_void_v<_Ty>> {};

我們從內往外開始分析,它的執行流程如下

  • 調用remove_cv_t去除const與volatile屬性。
  • 借助is_same_v模板,判斷參數類型_Ty與void是否相同。
  • 將判斷的結果作為bool_constant的參數,此時bool_constant類型為integral_constant<bool,result>。
  • is_void繼承自指定版本的bool_constant。
  • 下面我們來實際使用一下

    #include<iostream> #include<type_traits> using namespace std;int main() {cout << typeid(is_void<int>::type).name() << endl;cout << is_void<int>::value << endl;cout << typeid(is_void<void>::type).name() << endl;cout << is_void<void>::value << endl;return 0; }------------輸出結果------------ struct std::integral_constant<bool,0> 0 struct std::integral_constant<bool,1> 1

    至于其他一些類型的萃取函數,其實都與上面的大致相同,唯一不同的地方就是is_type_v這里的類型判斷的邏輯,例如:

    template <class _Ty> struct is_union : bool_constant<__is_union(_Ty)> {}; // determine whether _Ty is a uniontemplate <class _Ty> _INLINE_VAR constexpr bool is_union_v = __is_union(_Ty);// STRUCT TEMPLATE is_class template <class _Ty> struct is_class : bool_constant<__is_class(_Ty)> {}; // determine whether _Ty is a classtemplate <class _Ty> _INLINE_VAR constexpr bool is_class_v = __is_class(_Ty);// STRUCT TEMPLATE is_fundamental template <class _Ty> _INLINE_VAR constexpr bool is_fundamental_v = is_arithmetic_v<_Ty> || is_void_v<_Ty> || is_null_pointer_v<_Ty>;template <class _Ty> struct is_fundamental : bool_constant<is_fundamental_v<_Ty>> {}; // determine whether _Ty is a fundamental type

    遺憾的是C++標準庫中并沒有給出這些復雜類型的判斷代碼,在這里也就不過多的進行講解了。


    總結

    以上是生活随笔為你收集整理的还搞不懂STL的type_traits?从源码来带你一起分析的全部內容,希望文章能夠幫你解決所遇到的問題。

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

    主站蜘蛛池模板: 深夜福利免费视频 | 一级国产特黄bbbbb | 99黄色片| 国产香蕉av | 成年人网站av| 有码中文字幕 | 亚洲少妇第一页 | 国内视频一区二区 | 歪歪6080 | 日韩精品在线观看AV | 日韩国产精品一区 | 人妖天堂狠狠ts人妖天堂狠狠 | 国产精品美女久久久久av超清 | 欧美日韩乱 | 中文字幕一区二区三区波野结 | 四虎永久免费观看 | 黄色第一网站 | 人妻妺妺窝人体色www聚色窝 | 亚洲爱 | 国产欧美自拍 | 亚洲a色 | 99爱爱| 成人91网站| 日韩色图片 | 国产91精品久久久 | 妖精视频一区二区三区 | 精品人妻av一区二区三区 | a级片免费看 | 日本r级电影在线观看 | 欧美成免费 | 色综合激情 | 午夜香蕉视频 | 国产成人综合视频 | 国产一级视频 | 欧美精品一区二区三区蜜臀 | 黑人和白人做爰 | 污片免费观看 | 日韩中文娱乐网 | 在线观看黄色片网站 | 亚洲Av无码成人精品区伊人 | 四虎一区二区 | 夜夜操影视 | 777欧美 | 超碰福利在线观看 | 久草视频免费 | 国产欧美不卡 | 中出少妇| 91色呦呦| 黄色不卡av | 中国一级特黄真人毛片免费观看 | 国产精品18p | 在线播放黄色网址 | 三级做爰在线观看视频 | 国产成人无码精品久久久性色 | 国产精品免费在线 | 免费在线毛片 | 久久久不卡国产精品一区二区 | 久久精品久久久 | 色偷偷免费费视频在线 | 91久久精品国产91性色69 | 无码精品黑人一区二区三区 | 日本一区三区 | 日韩欧美综合 | 日韩福利视频导航 | 强制高潮抽搐哭叫求饶h | 99热18 | 久久久久久久国产精品毛片 | 中文字幕国产在线 | www在线 | 国产精品成人av久久 | 日本少妇videos高潮 | 午夜视频入口 | 最新天堂在线视频 | 国产精品三级在线观看无码 | 6080电视影片在线观看 | 涩涩涩在线视频 | 国产人妻久久精品一区二区三区 | 香蕉成人网 | 涩涩屋视频| 亚洲欧美精品在线 | 久久免费视频2 | 夜夜撸影院| 日韩欧美精品 | 一区二区免费在线观看视频 | 亚洲综合少妇 | 国产ts在线视频 | 亚洲伦理中文字幕 | 青青草视频国产 | 中文字幕久久熟女蜜桃 | 青青操原 | 手机在线观看毛片 | 91小视频| 日韩中文字幕一区二区 | 日韩欧美大陆 | 污污网站在线看 | 天狂传说之巴啦啦小魔仙 | 久久久在线观看 | 一级片特黄 | 毛色毛片|