C ++ technology used by STL (4) -- Heavy Load Functions

Source: Internet
Author: User

STL is an important part of the C ++ standard library. It is not only a reusable component library, but also a software framework that contains algorithms and data structures, it is also a good example of C ++ generic programming. Many advanced C ++ technologies are used in STL. This topic describes overload functions. Mainly refer to "C ++ Primer" and "STL source code analysis".

Someone may ask, where has the STL used a large number of templates and overload functions been used? First, we introduce the concept of overload functions. These two functions appear in the same scope. If they have the same name but different form parameters, they are called overloaded functions.
Function ). This is the definition of the overload function in C ++ Primer. In STL, when talking about overload functions, you must first introduce the iterator. The two seem to have little to do with each other. We know that the STL iterator has five features: value_type, pointer, reference, difference_type, and iterator_category. Value_type is described in the previous two articles, indicating the data type referred to by the iterator. This article introduces iterator_category.

Iterator_category indicates the iterator category. There are five types. Input_iterator, output_iterator, forward_iterator, bidirectional_iterator, and random_access_iterator are read-only, write-only, forward-moving, bidirectional, and random. Any iterator belongs to one of the classes. For example, the iterator of a single-chain table belongs to forward_iterator, And the iterator of the chain table belongs
Bidirectional_iterator, while the iteration of the dual-end queue belongs to random_access_iterator. The following is an example of the Code.

Template <class T, class Ref, class Ptr> <br/> struct Slist_iterator // single-chain table <br/>{< br/> typedef T value_type; // data type referred to by the iterator <br/> typedef ptrdiff_t difference_type; // distance between the two iterators <br/> typedef Ptr pointer; // data referred to by the iterator, change is not allowed, that is, when the right value <br/> typedef Ref reference; // data referred to by the iterator, change is allowed, that is, when the left value <br/> typedef forward_iterator_tag iterator_category; // move forward <br/>... <br/>}; <br/> template <class T, class Ref, class Ptr> <br/> struct List_iterator // bidirectional linked list <br/> {<br/> typedef ptrdiff_t difference_type; <br/> typedef T value_type; <br/> typedef Ptr pointer; <br/> typedef Ref reference; <br/> typedef bidirectional_iterator_tag iterator_category; // bidirectional <br/>... <br/>}; <br/> template <class T, class Ref, class Ptr> <br/> struct Deque_iterator // double-end queue <br/>{< br/> typedef T value_type; <br/> typedef ptrdiff_t difference_type; <br/> typedef Ptr pointer; <br/> typedef Ref reference; <br/> typedef random_access_iterator_tag iterator_category; // random <br/>... <br/> };

After talking about this, what is the relationship with overload functions? The next function is clear. This function is the advance function, which is used to move the iterator. The following is the definition of the function, which is taken from HP's STL source code and modified. It is easy to see that the external interface is the advance function and three overload functions are used internally. The third parameter of these functions is very interesting, but it is only a type with no variable name. This parameter is only used to activate overload. It's amazing. It's a powerful C ++.

Here, we need to reload the function to take efficiency into account. For a dual-end queue, its iterator supports random read/write, so calling the third function is obviously more efficient than calling the first function. Obviously, this improvement in efficiency is closely related to the ability of the iterator to move. Some functions in STL adopt this policy, such as distance function, to improve efficiency.

Template <class InputIterator, class Distance> <br/> inline void advance (InputIterator & I, Distance n) <br/>{< br/> _ advance (I, n, iterator_category (I); <br/>}< br/> template <class InputIterator, class Distance> <br/> inline void _ advance (InputIterator & I, Distance n, input_iterator_tag) // The first function <br/>{< br/> while (n --) ++ I; <br/>}< br/> template <class BidirectionalIterator, class Distance> <br/> inline void _ advance (BidirectionalIterator & I, Distance n, bidirectional_iterator_tag) // second function <br/>{< br/> if (n> = 0) <br/> while (n --) ++ I; <br/> else <br/> while (n ++) -- I; <br/>}< br/> template <class RandomAccessIterator, class Distance> <br/> inline void _ advance (RandomAccessIterator & I, Distance n, random_access_iterator_tag) // The third function <br/>{< br/> I + = n; <br/>}

At this point, the use of heavy duty functions in STL is almost introduced, but there are two questions. (1) The _ advance function provides three overloaded versions. Why isn't the inline void _ advance (InputIterator & I, Distance n, forward_iterator_tag) defined? (2) how to obtain the iterator type? That is, how to implement the above iterator_category (I) call.

For the first question, we know that the iterator type of the single-chain table is forward_iterator, and _ advance seems to have no optional functions for calling. In fact, this is related to the iterator classification in STL. The following is the relationship representation of the iterator classification, which is implemented by designing a label class for the iterator. The _ advance function activates the overload through these label classes. The Code is as follows:

// Relationship between various types of iterator <br/> struct input_iterator_tag {}; <br/> struct output_iterator_tag {}; <br/> struct forward_iterator_tag: public signature {}; <br/> struct bidirectional_iterator_tag: public forward_iterator_tag {}; <br/> struct random_access_iterator_tag: public bidirectional_iterator_tag {};

From the relationship defined above, we find that forward_iterator_tag inherits from Input_iterator_tag. Therefore, for the forward_iterator class iterator, its label is forward_iterator_tag, which is converted upwards, you can call the overload version whose label is Input_iterator_tag. You can write a program to verify it.

# Include <iostream> <br/> using namespace std; </p> <p> // iterator classification. The first character is uppercase, <br/> struct Input_iterator_tag {}; <br/> struct Output_iterator_tag {}; <br/> struct Forward_iterator_tag: public Input_iterator_tag {}; <br/> struct Bidirectional_iterator_tag: public Forward_iterator_tag {}; <br/> struct Random_access_iterator_tag: public Bidirectional_iterator_tag {}; </p> <p> template <class I> <br/> void foo (I & I, Input_iterator_tag) <br/>{< br/> cout <"Input_iterator_tag version" <endl; <br/>}< br/> template <class I> <br/> void foo (I & I, Bidirectional_iterator_tag) <br/>{ <br/> cout <"Bidirectional_iterator_tag version" <endl; <br/>}< br/> template <class I> <br/> void foo (I & I, Random_access_iterator_tag) <br/>{< br/> cout <"Random_access_iterator_tag version" <endl; <br/>}</p> <p> int main () <br/> {<br/> int * x; <br/> foo (x, Input_iterator_tag (); // The output is Input_iterator_tag version. <br/> foo (x, forward_iterator_tag (); // The output is Input_iterator_tag version <br/> foo (x, random (); // The output is bidirectionctional_iterator_tag version <br/> foo (x, random_access_iterator_tag (); // The output is Random_access_iterator_tag version <br/> return 0; <br/>}

For the second question, it seems that I have encountered it. It was mentioned in the Introduction of template specialization. The built-in type and template technology are used. STL still uses these technologies to solve this problem. Extend the extraction agent. The new definition of extraction agent is given below, and test cases are given. The test has passed in VS2008.

For more information about embedded types and template features, see C ++ technology used by STL (2)-template features

# Include <vector> <br/> # include <list> <br/> # include <deque> <br/> # include <iostream> <br/> using namespace std; </p> <p> // extraction agent <br/> template <class I> <br/> struct Iterator_traits {<br/> typedef typename I: value_type; <br/> typedef typename I: iterator_category; // type of the iterator <br/> }; <br/> // native special pointer <br/> template <class T> <br/> struct Iterator_traits <T * >{< br/> typedef T value_type; <br/> typedef random_access_iterator_tag iterator_category; <br/> }; <br/> // special native regular pointer <br/> template <class T> <br/> struct Iterator_traits <const T * >{< br/> typedef T value_type; <br/> typedef random_access_iterator_tag iterator_category; <br/>}; </p> <p> # define VALUE_TYPE (I) Iterator_traits <I >:: value_type () <br/> # define ITERATOR_CATEGORY (I) Iterator_traits <I >:: iterator_category () </p> <p> // custom advance function, similar to STL <br/> template <class InputIterator, class Distance> <br/> inline void MyAdvance (InputIterator & I, Distance n) <br/>{< br/> _ MyAdvance (I, n, ITERATOR_CATEGORY (InputIterator )); // extraction iterator type <br/>}< br/> template <class InputIterator, class Distance> <br/> inline void _ MyAdvance (InputIterator & I, Distance n, input_iterator_tag) <br/>{< br/> while (n --) + + I; <br/> cout <"InputIterator" <endl; <br/>}< br/> template <class BidirectionalIterator, class Distance> <br/> inline void _ MyAdvance (bidirealialiterator & I, Distance n, bidirectional_iterator_tag) <br/>{< br/> if (n> = 0) <br/> while (n --) + + I; <br/> else <br/> while (n ++) -- I; <br/> cout <"BidirectionalIterator" <endl; <br/>}< br/> template <class RandomAccessIterator, class Distance> <br/> inline void _ MyAdvance (RandomAccessIterator & I, Distance n, random_access_iterator_tag) <br/> {<br/> I + = n; <br/> cout <"RandomAccessIterator" <endl; <br/>}< br/> // Test Program <br/> int main () <br/>{< br/> vector <int> v; <br/> v. push_back (1); <br/> v. push_back (2); <br/> list <int> l; <br/> l. push_back (1); <br/> l. push_back (2); <br/> deque <int> d; <br/> d. push_back (1); <br/> d. push_back (2); </p> <p> vector <int>: iterator iter1 = v. begin (); <br/> list <int>: iterator iter2 = l. begin (); <br/> deque <int>: iterator iter3 = d. begin (); <br/> MyAdvance (iter1, 1); // The iterator of the vector is a native pointer, so it is a RandomAccessIterator <br/> MyAdvance (iter2, 1 ); // The linked list iterator is bidirectional, so it is BidirectionalIterator <br/> MyAdvance (iter3, 1); // double-end queues support random read/write, therefore, it is RandomAccessIterator <br/> return 0; <br/>}

Reposted Source

Http://blog.csdn.net/wuzhekai1985

Related Article

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.