STL源碼剖析 迭代器的概念和traits編程技法

  • 迭代器:依序巡防某個聚合物(容器)所含的各個元素,但是不需要暴露這個聚合物的內部表述方式
  • 核心思想:將容器和算法分開,彼此獨立設計
  • 容器和算法的泛型化,均可以使用模板,使用迭代器連接容器和算法
  • 例子
template <class InputIterator,class T>
InputIterator find(InputIterator first,InputIterator last,const T& value){while (first != last && *first != value){++first;}return first;
}
  • 迭代器 是一種類似智能指針的對象,最為關鍵的操作是內容提領和成員訪問。
  • 因此最關鍵的操作是對operator* 和 operator->進行重載工作
  • 參考 智能指針auto_ptr? (參考思想)
void func(){auto_ptr<std::string>ps(new std::string("input_string"));std::cout << *ps << std::endl;        //輸出input_stringstd::cout << ps->size() << std::endl; //輸出 5//離開之前不需要使用delete進行資源的釋放 auto_ptr自動釋放內存
}
  • 使用new動態配置一個初始值為?input_string 的string對象,并將所得到的一個結果(原生指針) 作為auto_ptr<std::string>對象的初始數值?
  • auto_ptr里面放的是原生指針所指對象的型別,而不是原生指針的型別
  • auto_ptr 的簡單實現
template<class T>
class auto_ptr{
public:explicit auto_ptr(T* p = 0):pointee(p){}template<class U>auto_ptr(auto_ptr<U>& rhs):pointee(rhs.release()){}~auto_ptr(){delete pointee;}template <class U>auto_ptr<T>& operator=(auto_ptr<U>& rhs){if (this != rhs)reset(rhs.release());return *this;}T& operator*() const {return *pointee;}T& operator->() const {return pointee;}T* get() const {return pointee;}private:T* pointee;
};
  • 迭代器會暴露太多的細節,因此將迭代器交給了每一個專屬的 容器,這也就是為啥每一個容器都有自己的專屬迭代器的緣故
  • 如何判斷迭代器所指對象的型別?使用函數模板的參數推導機制

  • ?func()為對外的接口,實際操作是由func_impl()實現的
  • func_impl是一個函數模板 一旦被調用 編譯器會自動進行模板的參數推導,推導出型別T?
  • 迭代器所指對象的型別,稱為該迭代器的value type,雖然上面的參數型別的推導機制可以適用于value type,但是并非是通用的方法,如果value type必須用于函數的返回值,就無法使用template的參數推導機制,畢竟 這個只適用于參數的推導 ,不可以推導 函數的返回值
  • 解決上面問題的辦法? 聲明內嵌型別?

  • func()返回的型別必須加上關鍵詞typename,因為T是一個template的參數,在編譯器對其具現化之前,編譯器不知道T是什么東西,也就是編譯器無法知道MyIter<T>::value_type是什么類型,其代表的是一個型別?還是一個成員函數?還是數據成員?
  • 關鍵詞typename相當于告訴編譯器 這是一個型別,才可以順利通過編譯
  • 但是并不是所有的迭代器都是class type,原生指針就不是,如果不是class type是不可以為其定義內嵌型別的。但是STL容器必須接受原始指針作為一種迭代器,上述的辦法還是不足以解決這個問題,那么如何實現對于上述一般化概念針對特殊情況(例如 針對原生指針)進行特殊化處理呢?
  • 使用template partial specialization就可以實現 (偏特化)
  • 偏特化的含義:如果class template擁有一個以上的template參數,可以針對其中某個(或者數個,但不是全部)的template參數進行特殊化處理,即可以在泛化版本中提供一個特殊化的版本,也就是將泛化版本中的某些template參數賦予明確的指定
template <typename U,typename V,typename T>
class C{};
  • 偏特化很容易讓我們陷入一種誤區,比如偏特化一定是對template參數U或者V或者T或者某種組合指定某個參數值,這是不對的
  • 偏特化是提供另外一份template 定義式,但是本身仍然是templatized;針對任何template參數更進一步的條件限制所設計出來的一種特殊化版本
  • 例:這個泛型版本允許接受T為任何型別
template <typename T>
class C{};
  • 很容易接受他有如下形式的 偏特化設計
  • 這個特殊化版本 僅僅適用于“T為原始指針”的情形,T為原生指針是相較于 T為任何型別的更進一步的限制
template <typename T>
class C<T*>{ };
  • 解決內嵌型別未解決的問題,也就是 原生指針不是class,因此無法為其定義內嵌型別,因此可以針對 “迭代器之template參數為指針”設計特化版的迭代器
  • 這個class template專門用于 萃取 迭代器的特性,value_type正是迭代器特性之一
template <class I>
struct iteraor_traits{ //traits的含義是 "特性"typedef typename I::value_type value_type;
};
  • 這個traits的含義是 如果 I 定義有自己的value type通過這個traits就可以萃取得到的value_type就是I:: value_type,如果I定義有自己的value type 先前的func()可以進一步的改下成如下形式
template <class I>
typename iteraor_traits<I>::value_type //這一整行是函數的返回型別func(I ite){return *ite;}
  • 這新增的一層間接性,可以帶來的好處是什么呢?可以為traits 進行偏特化的設計
  • 令iterator_traits 擁有的一個偏特化的設計如下
template <class T>
struct iteraor_traits<T*>{ //偏特化版本 迭代器是一個原生指針typedef T value_type;};
  • 于是 原生指針int* 雖然不是一種class type 但是仍然可以通過traits取到value type
  • 注意:針對“指向常數對象的指針(pointer to const)” iterator_traits<const int *>::value_type
  • 上述得到的結果是const int,而不是int,原本是希望聲明一個暫時的變量,使得其類型和迭代器的類型value_type一致,但是現在被const修飾無法賦值,不滿足需求,因此當迭代器是一個 pointer to const的類型,只能另外設計一個偏特化版本,讓value type指向的是non const版本即可
template <class T>
struct iterator_traits<const T*>{//偏特化版本 當迭代器的類型是pointer-to-const的時候//萃取出來的型別是 T 而不是const Ttypedef T value_type;
};
  • 這樣的話 不管面對的是迭代器、原生指針int* 或者const int* 都可以通過traits 取出正確的 value type
  • 使用traits 萃取各個迭代器的特性,這里特性是指 迭代器的相應的型別,但是需要每一個迭代器都需要使用內嵌型別定義的方式定義出相應的型別

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/446290.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/446290.shtml
英文地址,請注明出處:http://en.pswp.cn/news/446290.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

.sql文件如何執行_干貨|一條SQL查詢語句是如何執行的

作者&#xff1a;wanber鏈接&#xff1a;https://blog.nowcoder.net/n/9e120e8f1314466bb44fe706b283dc20

STL源碼剖析 5中迭代器型別

最常使用的5種迭代器的型別 為 value_type、difference_type、pointer、reference、iterator_category。如果想要自己開發的容器和STL進行適配&#xff0c;就需要定義上述5種類型 iteraor_traits 必須針對傳入的型別為 pointer 或者 pointer-to-const設計偏特化版本 template &…

Python學習16 正則表達式3 練習題

用戶名匹配 1.用戶名匹配&#xff1a;由數字、大小寫字母、下劃線_、中橫線-組成&#xff0c;長度為6-12位&#xff0c;不能以數字開頭。 import re usernameab578_-SDF resultre.search(^[a-zA-Z_-][0-9a-zA-Z_-]{5,12}$,username) print(result)郵箱 2.驗證輸入的郵箱&…

加載tf模型 正確率很低_深度學習模型訓練全流程!

↑↑↑關注后"星標"Datawhale每日干貨 & 每月組隊學習&#xff0c;不錯過Datawhale干貨 作者&#xff1a;黃星源、奉現&#xff0c;Datawhale優秀學習者本文從構建數據驗證集、模型訓練、模型加載和模型調參四個部分對深度學習中模型訓練的全流程進行講解。一個成…

Python學習17 Turtle庫繪圖

學習網址&#xff1a;https://docs.python.org/zh-cn/3/library/turtle.html Turtle庫 Turtle庫是Python語言中一個很流行的繪制圖像的函數庫&#xff0c;一個小烏龜&#xff0c;在一個橫軸為x、縱軸為y的坐標系原點&#xff08;畫布中心&#xff09;&#xff0c;(0,0)位置開…

android ros 節點編寫_嵌入式的我們為什么要學ROS

前言本來是要寫一篇STM32移植ROS的一個小lib庫&#xff0c;ROS一般都是需要跑在Linux上的&#xff0c;STM32使用就是當成一個ROS通訊的小節點&#xff0c;但是寫文章時間不夠&#xff0c;所以就簡單做一篇ROS的介紹文章&#xff0c;分享給嵌入式的小伙伴們。ROS現在在機器人領域…

STL源碼剖析 __type_traits

traits編程 彌補了C本身的不足STL只對迭代器進行規范制定出了iterator_traits&#xff0c;SGI在此基礎上進一步擴展&#xff0c;產生了__type_traits雙下劃線的含義是這個是SGI內部使用的東西&#xff0c;不屬于STL標準iterator_traits 負責萃取迭代器的特性__type_traits負責萃…

java 學生成績

題目 對學生成績大于60分的&#xff0c;輸出“合格”。低于60分的&#xff0c;輸出“不合格” 代碼 使用/除法簡化代碼 package l1_switch_case;import java.util.Scanner;public class SwitchDemo2 {public static void main(String[] args) {Scanner scanner new Scanne…

STL源碼剖析 序列式容器|Vector

容器的概觀和分類 array 數組 、list 鏈表、tree樹 、stack堆棧、queue隊列、hash table散列表、set集合、map映射表根據數據在容器中的排列順序&#xff0c;將上述數據結構分為序列式和關聯式兩種類型SGI STL使用內縮方式來表達基層和衍生層之間的關系衍生不是派生&#xff0…

ansible 修改文件變量_Ansible Playbook中的變量與引用

Ansible是一個系列文章&#xff0c;我會盡量以通俗易懂、詼諧幽默的總結方式給大家呈現這些枯燥的知識點&#xff0c;讓學習變的有趣一些。Ansible自動化運維前言前面有說到使用playbook來搞一些復雜的功能&#xff0c;我們使用YAML來寫playbook&#xff0c;就像我們用其它語言…

java 判斷日期為第幾天

題目1 編寫程序&#xff1a;從鍵盤上輸入2019年的“month”和“day”&#xff0c;要求通過程序 輸出輸入的日期為2019年的第幾天。 代碼1 從12月往下加日期數 package l1_switch_case; import java.util.Scanner; public class SwitchDemo4 {public static void main(Strin…

STL源碼剖析 list概述

目錄 list的節點(node) list迭代器 list 的構造和內存管理 list 的元素操作 list相較于vector連續的線性空間就顯得很復雜&#xff0c;他的存儲空間是不連續的&#xff0c;好處是每次插入和刪除一個元素的時候&#xff0c;只需要配置或者釋放一個元素的空間 插入和刪除十分的…

vsftp不允許切換到其它目錄_IntelliJ IDEA如何對project的目錄進行篩選顯示?

如果你的項目很龐大&#xff0c;同一個功能用到的各種文件散落在多個文件夾&#xff0c;開發時切換不便&#xff0c;可以利用scope功能&#xff0c;只顯示該功能用到的文件&#xff0c;讓project列表十分清爽&#xff0c;提高開發效率。本文使用的IDEA版本為2020.1。1、打開sco…

java 年份對應的中國生肖

題目 編寫一個程序&#xff0c;為一個給定的年份找出其對應的中國生肖。 中國的生肖基于12年一個周期&#xff0c; 每年用一個動物代表&#xff1a; rat、ox、tiger、rabbit、dragon、snake、horse、sheep、monkey、 rooster、dog、pig。 提示&#xff1a;2019年&#xff1a;豬…

密碼學專題 對稱加密算法

一般來說&#xff0c;使用OpenSSL對稱加密算法有兩種方式&#xff0c;一種是使用API函數的方式&#xff0c;一種是使用OpenSSL提供的對稱加密算法指令方式。本書將介紹對稱加密算法的指令方式OpenSSL的對稱加密算法指令主要用來對數據進行加密和解密處理&#xff0c;輸入輸出的…

網絡防火墻單向和雙向_單向晶閘管與雙向晶閘管之間的不同之處

晶閘管是回一個可以控導點開關&#xff0c;能以弱電去控制強電的各種電路。晶閘管常用于整流&#xff0c;調壓&#xff0c;交直流變化&#xff0c;開關&#xff0c;調光等控制電路中。具有提交小&#xff0c;重量輕&#xff0c;耐壓高&#xff0c;容量大&#xff0c;效率高&…

java 遍歷100以內的偶數,偶數的和,偶數的個數

題目 遍歷100以內的偶數&#xff0c;偶數的和&#xff0c;偶數的個數 代碼 package l2_for; /*遍歷100以內的偶數&#xff0c;偶數的和&#xff0c;偶數的個數*/ public class ForDemo1 {public static void main(String[] args) {//方法1&#xff1a;int sum1 0,count10;f…

python版本切換_怎么切換python版本

展開全部 &#xff08;1&#xff09;分別安2113裝 python-2.7.12.amd64.msi python-3.5.2-amd64.exe &#xff08;python官網下載的&#xff09; 順序無所謂&#xff08;為5261了看著4102方便&#xff0c;我把安裝路徑修改統一了1653&#xff09; &#xff08;2&#xff09;配置…

java 打印

題目 編寫程序從1循環到150&#xff0c;并在每行打印一個值&#xff0c;另外在每個3的倍數行 上打印出“foo”,在每個5的倍數行上打印“biz”,在每個7的倍數行上打印 輸出“baz”。 代碼 package l2_for;/** 編寫程序從1循環到150&#xff0c;并在每行打印一個值&#xff0c…

react.lazy 路由懶加載_Vue面試題: 如何實現路由懶加載?

非懶加載import List from /components/list.vue const router new VueRouter({routes: [{ path: /list, component: List }] })方案一(常用)const List () > import(/components/list.vue) const router new VueRouter({routes: [{ path: /list, component: List }] })方…