1. 程式人生 > >STL之迭代器和Traits技法

STL之迭代器和Traits技法

在開始講迭代器之前,先列舉幾個例子,由淺入深的來理解一下為什麼要設計迭代器。

//對於int類的求和函式
int sum(int *a , int n)
{
    int sum = 0 ;
    for (int i = 0 ; i < n ; i++) {
        sum += *a++;
    }
    return sum;
}
//對於listNode類的求和函式
struct ListNode {
    int val;
    ListNode * next;
};
int sum(ListNode * head) {
    int sum = 0;
    ListNode *p = head;
    while
(p != NULL) { sum += p->val; p=p->next; } return sum; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

針對如上兩個函式,我們來談談這種設計的缺陷所在:

  • 遍歷int陣列和單鏈表listNode時,需要設計兩份不一樣的sum求和函式,對於STL這樣含有大量容器的程式碼庫,針對每一種容器都設計sum的話,過於冗雜
  • 在sum函式中暴露了太多設計細節,如ListNode的節點值型別int,和指向下一個節點的指標next
  • 對於int陣列來說,還必須知道陣列的大小,以免越界訪問
  • 演算法的設計過多的依賴容器,容器的改動會造成大量演算法函式的隨之改動

那麼,如何設計才能使得演算法擺脫特定容器?如何讓演算法和容器各自獨立設計,互不影響又能統一到一起?本篇部落格就帶你一窺STL的迭代器設計。

迭代器概述

迭代器是一種抽象的設計概念,在設計模式中是這麼定義迭代器模式的,即提供一種方法,使之能夠巡訪某個聚合物所含的每一個元素,而無需暴露該聚合物的內部表述方式。

不論是泛型思維或STL的實際運用,迭代器都扮演著重要的角色,STL的中心思想就在於:將資料容器和演算法分開,彼此獨立設計,最後再以一帖膠著劑將它們撮合在一起。

談到迭代器需要遍歷容器就想到指標,的確,迭代器就是一種類似指標的物件,而指標的各種行為中最常見也最重要的就是內容提領(dereference)和成員訪問(member access),因此,迭代器最重要的程式設計工作就是對operator*和operator->進行過載工作。

Traits程式設計技法

在介紹STL迭代器之前,先來看看Traits程式設計技法,通過它你能夠更好的理解迭代器設計。

template引數推導機制

我們先回過頭去看看sum函式,在sum函式中,我們必須知道容器的元素型別,這關係到函式返回值。既然迭代器設計中不能暴露容器的實現細節,那麼我們在演算法中是不可能知道容器元素的型別,因此,必須設計出一個機制,能夠提取出容器中元素的型別。看看如下示例程式碼:

#include <stdio.h>
#include <iostream>

using namespace std;

//此函式中並不知道iter所指的元素型別,而是通過模板T來獲取的
template <class I, class T1 ,class T>
T sum_impl(I iter ,T1 n , T t) {
    T sum = 0;//通過模板的特性,可以獲取I所指之物的型別,此處為int

    //這裡做func應該做的工作
    for(int i = 0 ; i < n ;i++){
        sum+=*iter++;
    } 
    return sum;
}

template <class I , class T1>
inline T1 sum(I iter , T1 n) {//此處暴露了template引數推導機制的缺陷,在型別用於返回值時便束手無策
    return sum_impl(iter , n ,*iter);
}

int main() {
    int a[5] = {1,2,3,4,5};
    int sum1 = sum(a , 5);
    cout<<sum1<<endl;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

上例中通過模板的引數推導機制推匯出了iter所指之物的型別(int),於是可以定義T sum變數。

然而,迭代器所指之物的型別並非只是”迭代器所指物件的型別“,最常用的迭代器型別有五種,並非任何情況下任何一種都可利用上述的template引數推導機制來獲取,而且對於返回值型別,template引數推導機制也束手無策,因此,Traits技法應運而生,解決了這一難題!

內嵌型別機制

Traits技法採用內嵌型別來實現獲取迭代器型別這一功能需求,具體怎麼實現的呢?我們看下面的程式碼:

#include <stdio.h>
#include <iostream>

using namespace std;
//定義一個簡單的iterator
template <class T>
struct MyIter{
    typedef T value_type; // 內嵌型別宣告
    T* ptr;
    MyIter(T* p =0):ptr(p){}
    T& operator*() const {return *ptr;}
};

template <class I>
typename I::value_type // func返回值型別
func(I iter){
    return *iter;
}

int main(){
    MyIter<int> iter(new int(8));
    cout<<func(iter)<<endl;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

注意,func()函式的返回值型別必須加上關鍵詞typename,因為T是一個template引數,在它被編譯器具現化之前,編譯器對其一無所知,關鍵詞typename的用意在於告訴編譯器這是一個型別,如此才能通過編譯。

內嵌型別看起來不錯,可以很順利的提取出迭代器所指型別並克服了template引數推導機制不能用於函式返回值的缺陷。可是,並不是所有的迭代器都是class type,原聲指標就不是!如果不是class type,那麼就無法宣告內嵌型別。但是STL絕對必須接受原生指標作為一個迭代器。因此,必須另行它法!

iterator_traits萃取機

針對原生指標這類特殊情況,我們很容易想到利用模板偏特化的機制來實現特殊宣告,在泛化設計中提供一個特化版本。偏特化的定義是:針對任何template引數更進一步的條件限制所設計出來的一個特化版本。這裡,針對上面的MyIter設計出一個適合原生指標的特化版本,如下:

template <class T>
struct MyIter <T*>{   //T*代表T為原生指標,這便是T為任意型別的一個更進一步的條件限制
    typedef T value_type; // 內嵌型別宣告
    T* ptr;
    MyIter(T* p =0):ptr(p){}
    T& operator*() const {return *ptr;}
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

有了上述的介紹,包括template引數推導,內嵌型別,模板偏特化等,下面STL的真正主角要登場了,STL專門設計了一個iterator_traits模板類來”萃取“迭代器的特性。其定義如下:

// 用於traits出迭代其所指物件的型別
template <class I>
struct iterator_traits
{
  typedef typename I::value_type        value_type;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

這個類如何完成迭代器的型別萃取呢?我們繼續往下看:

template <class I>
typename iterator_traits<I>::value_type // 通過iterator_traits類萃取I的型別
func(I iter){
    return *iter;
}
  • 1
  • 2
  • 3
  • 4
  • 5

從表面上來看,這麼做只是多了一層間接性,但是帶來的好處是極大的!iterator_traits類可以擁有特化版本,如下:

//原生指標特化版本
template <class T>
struct iterator_traits <T*>
{
  typedef T  value_type;
}
//const指標特化版本
template <class T>
struct iterator_traits <const T*>
{
  typedef T  value_type;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

於是,原生指標int*雖然不是一種class type,也可以通過traits取其value,到這裡traits的思想就基本明瞭了!下面就來看看STL只能中”萃取機“的原始碼

// 用於traits出迭代其所指物件的型別
template <class Iterator>
struct iterator_traits
{
  // 迭代器型別, STL提供五種迭代器
  typedef typename Iterator::iterator_category iterator_category;

  // 迭代器所指物件的型別
  // 如果想與STL演算法相容, 那麼在類內需要提供value_type定義
  typedef typename Iterator::value_type        value_type;

  // 這個是用於處理兩個迭代器間距離的型別
  typedef typename Iterator::difference_type   difference_type;

  // 直接指向物件的原生指標型別
  typedef typename Iterator::pointer           pointer;

  // 這個是物件的引用型別
  typedef typename Iterator::reference         reference;
};
// 針對指標提供特化版本
template <class T>
struct iterator_traits<T*>
{
  typedef random_access_iterator_tag iterator_category;
  typedef T                          value_type;
  typedef ptrdiff_t                  difference_type;
  typedef T*                         pointer;
  typedef T&                         reference;
};

// 針對指向常物件的指標提供特化
template <class T>
struct iterator_traits<const T*>
{
  typedef random_access_iterator_tag iterator_category;
  typedef T                          value_type;
  typedef ptrdiff_t                  difference_type;
  typedef const T*                   pointer;
  typedef const T&                   reference;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

對於原始碼中的五種迭代器型別在下一小節中會有詳細說明。

迭代器設計

迭代器型別

value_type

所謂value_type,是指迭代器所指物件的型別,在之前的示例中已經介紹得很清楚了,這裡就不再贅述。

difference_type

difference_type用來表示兩個迭代器之間的距離,因此它也可以用來表示一個容器的最大容量。下面以STL裡面的計數功能函式count()為例,來介紹一下difference_type的用法。

template <class I,class T>
typename iterator_traits<I>::difference_type   //返回值型別
count(I first , I end , const T& value){
    typename iterator_traits<I>::difference_type n = 0;  
    for( ; first!=end ; ++first){
        if(*first == value) ++n;
    }
    return n;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

針對原生指標和原生的const指標,iterator_traits的difference_type為ptrdiff_t(long int),特化版本依然可以採用iterator_traits::difference_type來獲取型別。

reference_type

從“迭代器所指之物的內容是否可以改變”的角度可以將迭代器分為兩種:

  • const迭代器:不允許改變“所指物件之內容”,例如const int* p
  • mutable迭代器:允許改變“所指物件之內容”,例如int* p

當我們要對一個mutable迭代器進行提領(reference)操作時,獲得的不應該是一個右值(右值不允許賦值操作),而應該是一個左值,左值才允許賦值操作。

故:
+ 當p是一個mutable迭代器時,如果其value type是T,那麼*p的型別應該為T&;
+ 當p是一個const迭代器時,*p的型別為const T&

pointer type

迭代器可以傳回一個指標,指向迭代器所指之物。再迭代器原始碼中,可以找到如下關於指標和引用的實現:

Reference operator*() const { return *value; }
pointer operator->() const { return &(operator*()); }
  • 1
  • 2

在iterator_traits結構體中需要加入其型別,如下:

template <class Iterator>
struct iterator_traits
{
  typedef typename Iterator::pointer           pointer;
  typedef typename Iterator::reference         reference;
}
//針對原生指標的特化版本
template <class T>
struct iterator_traits<T*>
{
  typedef T*                         pointer;
  typedef T&                         reference;
};
//針對原生const指標的特化版本
template <class T>
struct iterator_traits<const T*>
{
  typedef const T*                   pointer;
  typedef const T&                   reference;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

iterator_category

這一型別代表迭代器的類別,一般分為五類:

  • Input Iterator:只讀(read only)
  • Output Iterator:只寫(write only)
  • Forward Iterator:允許“寫入型”演算法在此迭代器所形成的區間上進行讀寫操作
  • Bidirectional Iterator:可雙向移動的迭代器
  • Random Access Iterator:前四種迭代器都只供應一部分指標的算數能力(前三種支援operator++,第四種支援operator–),第五種則涵蓋所有指標的算數能力,包括p+n,p-n,p[n],p1-p2,p1
// 用於標記迭代器型別
struct input_iterator_tag {};
struct output_iterator_tag {};
struct forward_iterator_tag : public input_iterator_tag {};
struct bidirectional_iterator_tag : public forward_iterator_tag {};
struct random_access_iterator_tag : public bidirectional_iterator_tag {};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

迭代器的保證

為了符合規範,任何迭代器都應該提供五個內嵌型別,以利於Traits萃取,否則就自別與整個STL架構,可能無法與其他STL元件順利搭配。STL提供了一份iterator class如下:

//為避免掛一漏萬,每個新設計的迭代器都必須繼承自它
template <class Category, class T, class Distance = ptrdiff_t,
          class Pointer = T*, class Reference = T&>
struct iterator {
  typedef Category  iterator_category;
  typedef T         value_type;
  typedef Distance  difference_type;
  typedef Pointer   pointer;
  typedef Reference reference;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

迭代器原始碼(完整版)

/**
 * 用於標記迭代器型別
 */
struct input_iterator_tag {};
struct output_iterator_tag {};
struct forward_iterator_tag : public input_iterator_tag {};
struct bidirectional_iterator_tag : public forward_iterator_tag {};
struct random_access_iterator_tag : public bidirectional_iterator_tag {};

/**
 * 用於traits出迭代其所指物件的型別
 */
template <class Iterator>
struct iterator_traits
{
  // 迭代器型別, STL提供五種迭代器
  typedef typename Iterator::iterator_category iterator_category;

  // 迭代器所指物件的型別
  // 如果想與STL演算法相容, 那麼在類內需要提供value_type定義
  typedef typename Iterator::value_type        value_type;

  // 這個是用於處理兩個迭代器間距離的型別
  typedef typename Iterator::difference_type   difference_type;

  // 直接指向物件的原生指標型別
  typedef typename Iterator::pointer           pointer;

  // 這個是物件的引用型別
  typedef typename Iterator::reference         reference;
};

/**
 * 針對指標提供特化版本
 */
template <class T>
struct iterator_traits<T*>
{
  typedef random_access_iterator_tag iterator_category;
  typedef T                          value_type;
  typedef ptrdiff_t                  difference_type;
  typedef T*                         pointer;
  typedef T&                         reference;
};
/**
 * 針對指向常物件的指標提供特化
 */
template <class T>
struct iterator_traits<const T*>
{
  typedef random_access_iterator_tag iterator_category;
  typedef T                          value_type;
  typedef ptrdiff_t                  difference_type;
  typedef const T*                   pointer;
  typedef const T&                   reference;
};
/**
 *  返回迭代器類別
 */
template <class Iterator>
inline typename iterator_traits<Iterator>::iterator_category
iterator_category(const Iterator&)
{
  typedef typename iterator_traits<Iterator>::iterator_category category;
  return category();
}
/**
 * 返回表示迭代器距離的型別
 */
template <class Iterator>
inline typename iterator_traits<Iterator>::difference_type*
distance_type(const Iterator&)
{
  return static_cast<typename iterator_traits<Iterator>::difference_type*>(0);
}
/**
 * 返回迭代器所指物件的型別
 */
template <class Iterator>
inline typename iterator_traits<Iterator>::value_type*
value_type(const Iterator&)
{
  return static_cast<typename iterator_traits<Iterator>::value_type*>(0);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84

迭代器相關函式設計

distance函式

distance函式用來計算兩個迭代器之前的距離。

  • 針對Input Iterator,Output Iterator,Forward Iterator,Bidirectional Iterator來說,必須逐一累加計算距離
  • 針對random_access_iterator來說,支援兩個迭代器相減,所以直接相減就能得到距離

其具體實現如下:

/**
 * 針對Input Iterator,Output Iterator,Forward Iterator,Bidirectional Iterator
 * 這四種函式,需要逐一累加來計算距離
 */
template <class InputIterator>
inline iterator_traits<InputIterator>::difference_type
__distance(InputIterator first, InputIterator last, input_iterator_tag)
{
  iterator_traits<InputIterator>::difference_type n = 0;
  while (first != last) {
    ++first; ++n;
  }
  return n;
}
/**
 * 針對random_access_iterator,可直接相減來計算差距
 */
template <class RandomAccessIterator>
inline iterator_traits<RandomAccessIterator>::difference_type
__distance(RandomAccessIterator first, RandomAccessIterator last,
           random_access_iterator_tag)
{
  return last - first;
}
// 入口函式,先判斷迭代器型別iterator_category,然後呼叫特定函式
template <class InputIterator>
inline iterator_traits<InputIterator>::difference_type
distance(InputIterator first, InputIterator last)
{
  typedef typename iterator_traits<InputIterator>::iterator_category category;
  return __distance(first, last, category());
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

Advance函式

Advance函式有兩個引數,迭代器p和n,函式內部將p前進n次。針對不同型別的迭代器有如下實現:

  • 針對input_iterator和forward_iterator,單向,逐一前進
  • 針對bidirectional_iterator,雙向,可以前進和後退,n>0和n<0
  • 針對random_access_iterator,支援p+n,可直接計算

其程式碼實現如下:

/**
 * 針對input_iterator和forward_iterator版本
 */
template <class InputIterator, class Distance>
inline void __advance(InputIterator& i, Distance n, input_iterator_tag)
{
  while (n--) ++i;
}
/**
 * 針對bidirectional_iterator版本
 */
template <class BidirectionalIterator, class Distance>
inline void __advance(BidirectionalIterator& i, Distance n,
                      bidirectional_iterator_tag)
{
  if (n >= 0)
    while (n--) ++i;
  else
    while (n++) --i;
}
/**
 * 針對random_access_iterator版本
 */
template <class RandomAccessIterator, class Distance>
inline void __advance(RandomAccessIterator& i, Distance n,
                      random_access_iterator_tag)
{
  i += n;
}
/**
 * 入口函式,先判斷迭代器的型別
 */
template <class InputIterator, class Distance>
inline void advance(InputIterator& i, Distance n)
{
  __advance(i, n, iterator_category(i));
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

附加:type_traits設計

iterator_traits負責萃取迭代器的特性;type_traits負責萃取型別的特性。

帶你深入理解STL之空間配置器(思維導圖+原始碼)一篇部落格中,講到需要根據物件建構函式和解構函式的trivial和non-trivial特性來採用最有效的措施,例如:如果建構函式是trivial的,那麼可以直接採用如malloc()和memcpy()等函式,來提高效率。

例如:如果拷貝一個未知型別的陣列,如果其具有trivial拷貝建構函式,那麼可以直接利用memcpy()來拷貝,反之則要呼叫該型別的拷貝建構函式。

type_traits的原始碼實現如下:

/**
 * 用來標識真/假物件,利用type_traits響應結果來進行引數推導,
 * 而編譯器只有面對class object形式的引數才會做引數推導,
 * 這兩個空白class不會帶來額外負擔
 */
struct __true_type{};
struct __false_type{};

/**
 * type_traits結構體設計
 */
template <class type>
struct __type_traits
{
    // 不要移除這個成員
    // 它通知能自動特化__type_traits的編譯器, 現在這個__type_traits template是特化的
    // 這是為了確保萬一編譯器使用了__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;
};
// 特化型別:
//         char, signed char, unsigned char,
//         short, unsigned short
//         int, unsigned int
//         long, unsigned long
//         float, double, long double
/**
 * 以下針對C++內建的基本資料型別提供特化版本, 
 * 使其具有trivial default constructor,
 * copy constructor, assignment operator, destructor並標記其為POD型別
 */
__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;
};
//針對char的特化版本
__STL_TEMPLATE_NULL struct __type_traits<signed 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;
};
//針對unsigned char的特化版本
__STL_TEMPLATE_NULL struct __type_traits<unsigned 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;
};
//針對short的特化版本
__STL_TEMPLATE_NULL struct __type_traits<short>
{
   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;
};
//針對unsigned short的特化版本
__STL_TEMPLATE_NULL struct __type_traits<unsigned short>
{
   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;
};
//針對int的特化版本
__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;
};
//針對unsigned int的特化版本
__STL_TEMPLATE_NULL struct __type_traits<unsigned 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;
};
//針對long的特化版本
__STL_TEMPLATE_NULL struct __type_traits<long>
{
   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;
};
//針對unsigned long的特化版本
__STL_TEMPLATE_NULL struct __type_traits<unsigned long>
{
   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;
};
//針對float的特化版本
__STL_TEMPLATE_NULL struct __type_traits<float>
{
   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;
};
//針對double的特化版本
__STL_TEMPLATE_NULL struct __type_traits<double>
{
   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;
};
//針對long double的特化版本
__STL_TEMPLATE_NULL struct __type_traits<long double>
{
   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;
};

// 針對指標提供特化
template <class T>
struct __type_traits<T*>
{
   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;
};

// 針對char *, signed char *, unsigned char *提供特化

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;
};

struct __type_traits<
            
           

相關推薦

STLTraits技法

在開始講迭代器之前,先列舉幾個例子,由淺入深的來理解一下為什麼要設計迭代器。 //對於int類的求和函式 int sum(int *a , int n) { int sum = 0 ; for (int i = 0 ; i < n ;

STLtraits程式設計技法

iterator模式定義如下: 提供一種方法,使之能夠依序巡防某個聚合物所含的各個元素,而又不暴露該聚合物的內部表示式。 迭代器是一種smart pointer: 舉例auto_ptr template<class T> class auto_ptr { p

Python學習生成器

那麼首先什麼是迭代器和生成器呢? 迭代器即迭代的工具,那麼什麼又是迭代呢?所謂迭代:迭代是一個重複的過程,每次重讀即一次迭代,並且每次迭代的結果都是下一次迭代的初始值。例: l=[1,2,3] count=0 while count < len(l): print(l[count])

Python基本語法生成器

  迭代器       迭代是訪問集合類元素的一種方式,它可以記住遍歷的位置的物件,從集合的第一個元素開始訪問,直到所有的元素被訪問完結束,只能往前不會後退。字串、列表或元組物件都可用於建立迭代器。 迭代器有兩個基本的方法:iter()和nex

c++traits特性提取

轉自:點選開啟連結 一、迭代器的概念 迭代器是STL將資料容器和演算法分開後連線的紐帶,也是泛型思維發展的必然結果。泛型演算法就是通過迭代器操作容器的,使得演算法和容器本身分離開來。 迭代器模式:提供一種方式,可以依次訪問一個聚合物(容器)中所有元素而不暴露聚合物內部的表達

TypeScript基礎入門生成器

迭代性 如果物件具有Symbol.iterator屬性的實現,則該物件被視為可迭代。 一些內建型別,如Array,Map,Set,String,Int32Array,Uint32Array等,已經實現了Symbol.iterator屬性。 物件上的Symbol.iter

STL基礎--演算法

1 迭代器 Iterators 5種迭代器型別 隨機訪問迭代器: vector, deque, array // 允許的操作 vector<int> itr; itr = itr + 5; // itr往前移5步 itr = itr - 4; if (itr2 > it

C++ STL

一. 什麼是迭代器? 迭代器是STL中行為類似指標的設計模式,它可以提供了一種對容器中的物件的訪問方法;並且它沒有暴露容器中內部的表述方式。  例如STL中的map和set,它們的底層是一顆紅黑樹(一種平衡樹),而當你用迭代器去對他們進行訪問時,原本在紅黑樹中的二叉樹結構

STL 原始碼剖析】淺談 STL traits 程式設計技法

![攝於清華五道口](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b9cd144f2eeb4d85856e265bfc630591~tplv-k3u1fbpfcp-zoom-1.image) 大家好,我是小賀。 > 點贊再看,養成習慣 &

STL 1–std::begin()std::end()使用

迭代器是一個行為類似於指標的模板類物件。只需要迭代器iter指向一個有效物件,就可以通過使用*iter解引用的方式來獲取一個物件的引用。通常會使用一對迭代器來定義一段元素,可以是任意支援迭代器物件的元素,一段元素是一個通過起始迭代器指向第一個元素,通過結束迭代器指向最後一個元素的後一個位置的元素序列。一般使用

STL原始碼剖析(三)traits程式設計

文章目錄 1. 迭代器概念 1.1 基本概念 1.2 迭代器設計理念 2. 引出traits程式設計 3. traits程式設計 3.1 traits程式設計技術 3.2 partial special

STL原始碼分析

前言 迭代器是將演算法和容器兩個獨立的泛型進行調和的一個介面. 使我們不需要關係中間的轉化是怎麼樣的就都能直接使用迭代器進行資料訪問. 而迭代器最重要的就是對operator *和operator->進行過載, 使它表現的像一個指標. 型別 迭代器根據移動特性和實施操作

STL原始碼剖析》學習

一、迭代器作用        在設計模式中有一種模式叫迭代器模式,簡單來說就是提供一種方法,在不需要暴露某個容器的內部表現形式情況下,使之能依次訪問該容器中的各個元素,這種設計思維在STL中得到了廣泛的應用,是STL的關鍵所在,通過迭代器,容器和演算法可以有機的粘合在一

人工智慧Python16 生成器

有一個概念我們一直在用,但我們卻從來沒有認真的去深入剖析它-這個概念就是迭代。 迭代器 迭代的意思類似於迴圈,每一次重複的過程被稱為一次迭代的過程,而每一次迭代得到的結果會被用來作為下一次迭代的初始值。提供迭代方法的容器稱為迭代器,通常接觸的迭代器有序列

java基礎第十二篇集合、增強for迴圈、泛型

Collection介面中的常用方法: * 所有的子類子介面都是具有的 * 集合的方法:增刪改查 * * public boolean add(E e);//新增元素 返回值表示是否新增成功 * public boolean remove(Object o);//刪除元素,返回值表示是否刪除成

STL-空間配置traits程式設計技巧

目錄 記憶體分配和釋放 物件的構造和析構 traits要解決的問題 內嵌類別宣告解決非指標迭代器的情況 使用模板特例化解決普通指標的情況 迭代器相應類別

python基礎生成器

see per n) attribute product 原本 狀態 區別 開發 假如我現在有一個列表l=[‘a‘,‘b‘,‘c‘,‘d‘,‘e‘],我想取列表中的內容,有幾種方式? 首先,我可以通過索引取值l[0],其次我們是不是還可以用for循環來取值呀? 你有沒有仔細

Python生成器

OS 返回 內部 16px fun break 得到 urn b- 叠代器 一 叠代 # 叠代是一個重復的過程,每次重復即一次叠代,並且每次叠代的結果都是下一次叠代的

分部類

迭代器 迭代器是可以返回相同型別的值的有序序列的一段程式碼,可用作方法,運算子或get訪問器的程式碼體.迭代器程式碼使用yield return語句依次返回每個元素,yield break語句將終止迭代.可以在類中實現多個迭代器,每個迭代器必須像類成員一樣有唯一的名稱,並且可以在foreac

設計模式的藝術 行為型模式模式

前言 現在的電視機都配置了一個遙控器,使用者可以通過遙控器去選擇上一個或者下一個臺,我們只需要知道如何使用這個遙控器,而無須關注電視是怎麼把電視訊道放入其中的,在軟體實際的開發中,也有這麼一種類,它儲存著多個成員物件,這些類通常稱為聚合類,對應的物件稱為聚合物件。為了方便操作這些聚合物件,同時可