STL Source Learning (i) Iterator concepts and traits programming techniques _STL

Source: Internet
Author: User
Tags arithmetic traits

The central idea of the STL is to separate the data container from the algorithm, design each other independently, and then bring them together with a stick agent. The binder is the iterator, the purpose of the iterator design is to easily obtain (traverse) the data in the container without exposing the inner implementation of the container.

For example, when using a list iterator, the user never knows how the data is stored in the list. The advantage of this is that all STL algorithms only need to receive the most parameters of the iterator is enough, do not have the tube is which container iterator, as long as the data can be obtained through the iterator to change the data can be.

However, the implementation of the iterator is not that simple, because when using iterators, you might also need to know the type of data the iterator points to, such as the need to define a variable of the same type in some algorithms. This creates a contradiction, because neither want to expose the underlying data, and must know the type of data, later will see, through the traits technique, can easily get the type of the iterator refers to the types of extraction traits techniques

As a container-specific iterator, the data type iterator stored in the container is known (because it needs to be a template parameter), so if you define an inline type in an iterator, you can get the type of data that the iterator refers to, such as defining a myiter iterator

Template <class t>
struct myiter
{
    /* defines the alias of T
    /typedef t VALUE_TYPE;
    t* ptr;
    Myiter (t* p = 0): PTR (P) {}
    t& operator* () const {return *ptr;}
    //...
};

Templace <class i>
/* Use the embedded type I to get the data type of the iterator * *
TypeName I::value_type
func (i ite)
{
    return *ite;
}

//...
myiter<int> ite (new int (8));
cout << func (ITE);  Output 8

When you use a scope symbol to express a type, you need to add TypeName in front of it to explicitly indicate that it is a type. Since I is a template parameter, before being materialized, the compiler knows nothing about I and doesn't know what i::value_type is, so you need to explicitly tell the compiler that this is a type

Traits is the encapsulation of the data type method of the iterator referred to above embedded type, which is known as the "extraction" iterator feature, and Value_type is one of the iterator characteristics

/* Used for extraction iterator type, iterator pointing to element type etc
 * can be used directly using
 * Iterator_traits<i>::value_type to get iterators to point to element type * *
template < Class iterator>
struct iterator_traits {
  typedef typename Iterator::value_type        value_type;
};

With this extractor, if the iterator declares a value_type inline type, you can get the type of the iterator iterator by using the following method

Templace <class i>/
//function return type, extract the data type it holds through iterator_traits from I-TypeName
iterator_traits<i>:: Value_type 
func (I iter)
{return
    *iter;
}
Pointer-specific version of

An extra layer of indirection has the advantage of defining a special version for Iterator_traits, as the native pointer can also count as an iterator, so like iterator_traits\

/* The biased version of the native pointer, because there is no inline type for the pointer * *
template <class t>
struct iterator_traits<t*> {
  typedef T                          Value_type;
};

/* A biased version of the constant pointer/*
template <class t>
struct iterator_traits<const t*> {
  typedef T                          Value_ type;
};

With the above special version, when using the Iterator_traits\ inline type definition

The part of the iterator that only iterator_traits extraction is not easy to understand, and the rest is about the iterator type, including the value type, the data value type different the iterator points to, the iterator difference type reference type, The data reference type that the iterator points to pointer type, the data pointer type that the iterator points to iterator_category, the iterator type

These types are also defined in the extractor iterator_traits, which are used to extract the corresponding type, as in the Valut_type

 Iterator_traits<i>::value_type gets the iterator to point to the element type
 * by analogy * *
template <class iterator>
struct iterator_traits {
  typedef typename Iterator::iterator_category iterator_category;
  typedef typename Iterator::value_type        Value_type;
  typedef typename Iterator::d ifference_type   difference_type;
  typedef typename Iterator::p ointer           pointer;
  typedef typename Iterator::reference         Reference;

The value type is actually the type of the object that the iterator refers to, which is the template parameter T. Assuming that the myiter it iterator is used, the value type is an int

Difference type refers to the type of distance between iterators, such as the difference between two iterators, saving the distance between iterators, etc., and the type is difference type, which is usually a type of ptrdiff_t

The reference type refers to the reference type of the object that the iterator refers to, usually t&

The pointer type refers to the pointer type of the object that the iterator refers to, usually t*

  typedef T                          Value_type;
  typedef ptrdiff_t                  Difference_type;
  typedef t&                         Reference;
  typedef t*                         Pointer;
Iterator type

In STL, according to the arithmetic operation supported by the iterator, there are actually many kinds of iterators, which are input iterator read-only iterators, and can not change the object of the iterator. Only the + + operations Ouput iterator write-only iterators are supported, allowing changes to the object referred to by the iterator. Only + + operations forward iterator forward iterators are supported and can be read and write. Only + + operations bidirectional iterator bidirectional iterators are supported and can be read and written. Support + + and – operate random access iterator random iterators, read-write. Supports all pointer arithmetic operations, including +,-, +=,-=,++,–, etc.

As you can see, different types of iterators can provide different functions, but this also brings some problems, taking the advance function as an example, which moves the given iterator n steps, however, different types of iterators support different arithmetic operations, and if you use + +, it's too time-consuming for random iterators ( Because we can use + + directly. This is the role of the Iterator_category iterator type, combining the parameter derivation of the template to distinguish between different iterator types, while using the most efficient method for arithmetic operation

The function of parameter derivation of template function ensures that the most suitable overload function is chosen according to the parameter type, so in STL, five class definitions corresponding to five iterator types are provided.

/* Defines the iterator type, and each iterator will have its own iterator type in iterator_categories
 * because C + + does not support direct fetch type operations, it is necessary to derive different types of operation
using template parameter derivation. 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 {};

The inheritance relationships defined by these five classes are the same as the inheritance relationships between iterators, and the other five classes are empty because they function only as template parameters for function overloading

In the definition of an iterator, iterator_category is defined based on the most powerful iterator type supported by itself, as

  typedef random_access_iterator_tag Iterator_category;

In this way, when the advance function is used again, the class that corresponds to its own iterator type is passed in, and different functions can be invoked based on the template parameter derivation

/* To move the iterator i n step, n can be negative
/template <class Inputiterator, class distance>
inline void advance (inputiterator & I, Distance n) {/* different
    iterators support different operations
     * Read Only, write only, forward iterators only support + + operations
     * Bidirectional iterators support ++,--Operations
     * Random iterators support +=,-=,++,--operations
     * In order to select different __advance functions according to different iterators, the method of template parameter derivation is used to implement overload
    ///* Iterator_category () is also a template overload, which is used to create an iterator I tag object
     * According to the template parameter derivation, can realize __advance overload * *
  __advance (i, N, iterator_category (i));
}

The iterator type in the template parameter is the Inputiterator type because the STL sets the template parameter type to the weakest type (similar to the base class in the inheritance system), and the actual type is judged according to the actual type of I (similar to polymorphism in the inheritance system).

The Iterator_category function is used to get the tag object for the iterator

/* Returns the iterator type object, which returns a class object
 * This is because the template parameter derivation is only derived for class objects * *
template <class iterator>
Inline TypeName Iterator_traits<iterator>::iterator_category
iterator_category (const iterator&) {
  typedef TypeName iterator_traits<iterator>::iterator_category category;
  return category ();
}

At this point, depending on the third argument type of the __advance (i, N, iterator_category (i)) function call, the template parameter derivation can be implemented by calling different functions

/* __advance overload for read-only iterators
/template <class Inputiterator, class distance>
inline void __advance ( inputiterator& I, Distance N, Input_iterator_tag) {while
  (n--) ++i;
}


/* __advance overload for bidirectional iterators
/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.
}

/* For __advance overloads of Random iterators
/Template <class Randomaccessiterator, class distance>
inline void __advance ( randomaccessiterator& I, Distance N, 
                      random_access_iterator_tag) {
  i = = n;
}

The STL provides only three __advance function overloads, because of the above inheritance system. Because of the output iterator, the __advane action of the forward iterator is the same as that of the input iterator, so it is entirely possible to call up the corresponding function of the input iterator (like calling a function of a derived class, but this function does not exist in the derived class. The corresponding function of the base class is called up) summary

There are two difficulties in the part of the iterator, one is to realize type extraction through traits technique, the other is to implement function overload through the derivation of template parameters. But the real look at the source will find it is not difficult, of course, the STL needs internal iterators to follow its provisions, that is, the definition of the above five types

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.