STL source code analysis-Implementation of extraction programming (traits) technology, stltraits

Source: Internet
Author: User
Tags traits

STL source code analysis-Implementation of extraction programming (traits) technology, stltraits

1. Why?

By default, a template provides a single definition that can be used for any template parameters that you can think! However, for the person who writes the template, this method is not flexible, especially when the template parameter is a pointer, if you want to instantiate a parameter different from the type, it becomes impossible! Sometimes, it is impossible to disable the same instantiation! So it appears, Partial Specialization!

At the same time, when using the void * pointer, you can share code to the maximum extent and reduce code expansion!

2. What is it? In fact, it is user-defined features.Template <> is used to describe that this is a special version. A special version is designed for parameters of any template type to make further condition restrictions!To put it bluntly, it isSome heavy-duty priority selection mechanisms, Select the most appropriate bitwise template for instantiation!

3. Significance of Partial Specialization: We provide a special version for the general design (that is, some template parameters in the general version are explicitly specified to influence the template instantiation type );

4. one of its applications in STL: Traits programming techniques. The core point is to instantiate a template, whether it is a class instantiation template, a pointer, or a pointer to a constant, the types of template submission are all in line with program requirements !!! Therefore, Traits is also called a "Feature Extraction Machine" by Mr. Hou Jie (you can hand over the correct element type for both types and pointers )!

5. without the special feature, there will be no widespread use of the so-called Traits. Without Traits, STL may not be a treasure of C ++, without stl nb, C ++ may not be the language leader! It is precisely because of its small specialization that the iterator has made great achievements and separated the algorithm from the data structure!

1. The Traits programming techniques are described in the previous article!

2. A good use is in the iterator;

3. Why? The premise is that not all template types are class type, some are native pointers, but some point to const T *

However, typedef T value_type cannot be used to extract the correct element type;

4. Whether it is a native pointer int * or const int *, you can use traits to retrieve the correct value_type;

5. It is the indirect layer of traits that separates algorithms from data structures! This makes the iterator a binder so that STL can work together!

6. Therefore,Iterator_traits must be designed with a special version when the input type is pointer and pointer to const!

Introduction

The extract programming technology is used in STL,

Brief description of extraction technology STL in iterator

STL (Standard Template Library) is a set builder of C ++ generic programming (template technology). iterator plays an important role in STL. There are three important concepts in STL:

The important function of the iterator is to decouple the container and algorithm, or to decouple the data and operation. The algorithm uses the iterator as the input to get rid of the access to the specific container data. the container-generated iterator is used to traverse every element in the container and avoid exposing the internal data structure and implementation details of the container.

Here, an example of an algorithm is used to demonstrate the usage of the iterator:

template <class Iterator, class T>Iterator find(Iterator begin, Iterator end, const T& value){while (begin != end && *begin != value)++begin;return begin;}

Note the algorithm shown in this example.find()Can be used in a variety of containers (vector,map...), If there is no iterator, You need to implementfind()Algorithm.

Simple iterator

In the implementation of the iterator, you often need to access the type of the object referred to by the iterator.value type. Use embedded type statementtypedefYou can easily hide the object type, as shown in the following iterator:

templates <class T>struct Iterator {typedef T value_type;...};

Generic algorithms can passtypename Iterator::value_typeTo obtainvalue type.

template <class Iterator>typename Iterator::value_typegetValue(Iterator iter) {return *iter;}

Note keywordstypenameBecauseTIstemplateThe compiler does not know the parameter before it is instantiated.TIs it a type or another object,typenameIt is used to tell the compiler that this type can be compiled.

Concept of Extraction

In a simple iterator, the internal details of the object indicated by the embedded type declaration are well hidden and data and algorithms are separated. However, STL requires support for the iterator algorithms, native pointers should also be supported, such

Int array[4] = {1, 2, 3, 4};find(array, array+4, 3);

One problem exists here is that native pointers cannot be embedded with type declarations, so there is a need for multiple layers of encapsulation, and the extraction compilation technology came into being.
Traits programming technology is classified into four words: feature extraction. In the context of the iterator, the value type of the iterator is extracted. It can be conceptually considered that the type of the object referred to by the iterator is a feature of the iterator (traits)

template <class Iterator>struct iterator_traits {typedef typename Iterator::value_type value_type;...};

Withiterator_traitsTo rewrite the algorithm.getValue():

template <class Iterator>typename iterator_traits<Iterator>::value_typegetValue(Iterator iter) {return *iter;}

The advantage of multi-layer encapsulation is that,iterator_traitsIt is a C ++ class template, which can be customized for native pointers (Special iterators). <generic thinking> the template is customized as follows: for (any)templateThe parameter is further restricted by a specially designed version, while the native pointerT*,const T*Is a kind of special.

template <class T>struct iterator_traits<T*> {typedef T value_type;};template <class T>struct iterator_traits<const T*> {typedef T value_type;};

Whether the iterator is a custom class template or a native pointer (T*,const T*),struct iterator_traitsCan extract the correct value type

STL iterator

Value type is only a feature of the iterator (traits). In practice, the STL iterator defines a total of five features. In order to make the User-Defined iterator suitable for STL algorithms, STL makes a convention to write a base classstd::teratorAs long as the custom iterator inheritsstd::iterator,iterator_traitsWe can extract all the features of the iterator correctly, so that the custom iterator can be integrated into the STL family and use a variety of generic algorithms seamlessly:

Template <class Category, class Value, class Distance = ptrdiff_t, class Pointer = Value *, class Reference = Value &> struct iterator {typedef Category; typedef Value value_type; typedef Distance difference_type; typedef Pointer pointer; typedef Reference reference;}; the corresponding struct is defined as follows: template <class Iterator> struct {typedef typename Iterator: value_typevalue_type; typedef typename Iterator: difference_type struct; typedef typename Iterator: pointer; typedef typename Iterator: reference; typedef typename Iterator: iterator_category ;}; template <class T> struct iterator_traits <T *> {typedef T value_type; typedef ptrdiff_t difference_type; typedef T * pointer; typedef T & reference; typedef extends iterator_category ;}; template <class T> struct <const T *> {typedef T value_type; typedef ptrdiff_t difference_type; typedef const T * pointer; typedef const T & reference; typedef incluiterator_category ;};

The above iterators involve four other features, which are limited by space and will not be described. Interested readers will read the references below.

Type Extraction

The extraction (traits) programming technology makes upC++HoweverSTLIt only regulates the characteristics of the iterator and developsiterator_traits. Since this technology is so useful, it should be applied to more extensive application scenarios. sgi stl (STL version developed by the Silicon Graphics System) has made an attempt to apply it outside the world of the iterator, therefore, the concept of Type extraction is generated.

We know that,C++Custom types have many features, such as constructor, copy constructor, and destructor. On the other hand,C++Built-in type Integerint,longNo constructor, copy constructor, and destructor. based on these features, we can use the most effective measures to construct and assign values. For example, for built-in types, we do not need to call constructor or copy constructor, but directly use memory processing (malloc(),memcpy()) To achieve the highest efficiency, which significantly improves the performance of large-scale and frequently-operated containers.

Simple Example

To use these features in the type, you can define a Feature Extraction Machine for the type:__type_traits

struct __true_type {};struct __false_type {};Template <class T>struct __type_traits {typedef __false_type has_trivial_default_constructor;typedef __false_type has_trivial_destructor;};

Because embedded type declarations cannot represent true or false, we define struct here__true_typeAnd__false_type. By default, these features are based on the most conservative values. Then, based on the specific situation, the template is used to set a more optimistic value for the specific type. for example, the built-in int type definition template is special:

template <>struct __type_traits<int> {typedef __true_type has_trivial_default_constructor;typedef __true_type has_trivial_destructor;};

According to <STL source code analysis> introduction, Some compilers can analyze various types of programs and generate corresponding__type_traitTemplate specialization. Of course, for compilers that do not support this function, manually compile the template specialization to define a more optimistic value. Otherwise, the default value__false_typeWill take effect.

Sgi stl Extraction

Defined by SGI STL__type_traitsIn addition to the featureshas_trivial_default_constructorAndhas_trivial_destructorAnd other features, as described below:

<Pre name = "code" class = "cpp"> template <class type> struct _ type_traits {typedef _ true_type this_dummy_member_must_be_first; // customize typedef _ false_type handler for special compilers; typedef _ false_type has_trivial_copy_constructor; typedef _ false_type handler; typedef _ false_type has_trivial_destructor ;};
Application Scenario-copy 

Template Functionscopy()YesSTLA generic algorithm has many special templates to Improve the Performance in different scenarios. We hope to use the method of Raytheon in appropriate cases to achieve the highest performance, for example, for different types, depending on whether there is a copy constructor, it can have different operations:

// Copy an array whose elements are of any type. Use the most effective Copying Method template <class T> inline void copy (T * source, T * destination, int n) as appropriate) {copy (source destination, n, typename _ type_traits <T >:: has_trivial_copy_constructor ();} // copy an array, its element type does not have trival copy constructorstemplate <class T> void copy (T * source, T * destination, int n, _ false_type ){...} // copy an array with the element type trival copy constructorstemplate <class T> void copy (T * source, T * destination, int n, _ true_type ){...}
Application Scenario-destructor in the memory pool

In the implementation of the memory pool, the acquisition and release of the object's memory space are required. In general, to release the dynamic memory space of an object, you need to call the destructor of the object, therefore, you can define the Destructor template.destruct()To execute the destructor. On the other hand, if the object does not require the destructordestuct()Do nothing.

Template <class T> void destruct (T & t) {typedef typename type_traits <T>: has_trivial_destrutor operator ;__ destruct (t, has_trivial_destructor ());} template <class T >__ destruct (T & t, _ ture_type) {// destructor T} template <class T >__ destruct <T & t, _ false_type) {// nothing else}
Applying extract technology to convert Enumeration type to real type

In actual code writing, we often encounter this situation: an enumeration constant is known to obtain the corresponding real type, which can be solved by extraction technology, such as defining an enumeration constant:

Typedef enum FieldType {struct = 0, struct, struct, FIELDTYPE_INT16, struct, FIELDTYPE_INT32, FIELDTYPE_UINT32, FIELDTYPE_INT64, struct, struct, FIELDTYPE_DOUBLE, FIELDTYPE_CSTRING,} EFieldType; the extraction technology can be used to define the Extraction Machine VariableTypeTraits to obtain the actual type corresponding to the enumeration type: template <FieldType pt> struct VariableTypeTraits {typedef void SyntaxType ;};


The preceding meaning indicates that ifptHas a featurevoid, You can useVariableTypeTraits<pt>::SyntaxTypevoidExtracted. Of course, the above module is just an empty shell, because for different enumeration typesVariableTypeTraits<pt>::SyntaxTypeExtractvoidIs meaningless. In this case, the template features come in handy. Through the template features, you can define the corresponding types for each Enumeration type:

# Define struct (pt, type) \ template <> \ struct VariableTypeTraits <pt >\{\ typedef type SyntaxType ;\}; struct (FIELDTYPE_INT8, int8_t) struct (FIELDTYPE_UINT8, uint8_t) minute (Week, int16_t) minute (Week, uint16_t) minute (FIELDTYPE_INT32, int32_t) minute (FIELDTYPE_UINT32, uint32_t) minute (Week, int64_t) minute (Week, uint64_t) hour, float) VARIABLE_TYPE_TRAITS_HELPER (FIELDTYPE_DOUBLE, double) to avoid code duplication, the macro-defined implementation method is used. after defining the preceding content, you can easily obtain the actual type pointed to by the enumeration constant: void Fun (FieldType ft) {switch (ft) {case FIELDTYPE_INT32: typedef VariableTypeTraits <FIELDTYPE_INT32> :: syntaxType syntaxType; syntaxType foo ;...}

}Sample Code

First, I will organize the code snippets in the previous article into a complete program to deepen the reader's understanding of this usage.

// Traits_example1.cpp # include <stdio. h> # include <stdlib. h> # include <stdint. h> // define typedef enum FieldType {FIELDTYPE_UNDEFINED = 0, FIELDTYPE_INT8, FIELDTYPE_INT32 for Enumeration type definitions. // to simplify the problem, only two types are listed.} EFieldType; // use the Traits programming technique template <FieldType pt> struct VariableTypeTraits {typedef void SyntaxType ;}; template <> struct VariableTypeTraits <FIELDTYPE_INT8 >{ typedef int8_t SyntaxType ;}; template <> struct VariableTypeTraits <FIELDTYPE_INT32> {typedef int32_t SyntaxType ;}; // test the demo function void func (int8_t var) {fprintf (stdout, "type: int8_t; value: % d \ n ", var);} void func (int32_t var) {fprintf (stdout," type: int32_t; value: % d \ n ", var );} int main () {typedef struct <strong >:: SyntaxType int8_type; int8_type int8_a = 1; func (int8_a); typedef struct <strong >:syntaxtype int32_type; int32_type int32_ B = 2; func (int32_ B); return 0 ;}
Convert a real type to an enumeration type

Similarly, the extraction technology can be used to convert the real type to the enumeration type:

template <typename T>struct TypeTraits {static const FieldType FIELD_TYPE = FIELDTYPE_UNDEFINED;}

Note that the nested type statement cannot be used here (typedef), Because the enumerated variables are objects rather than types, the static constants of the class are used to define them.FIELD_TYPENext, you can define template-specific for each type without the template-specific type.FILED_TYPE=FIELDTYPE_UNDEFINED

#define TYPE_TO_FIELDTYPE(type, field_type) \template<> \struct TypeTraits<type> { \static const FieldType FIELD_TYPE = field_type; \};TYPE_TO_FIELDTYPE(int8_t, FIELDTYPE_INT8);TYPE_TO_FIELDTYPE(uint8_t, FIELDTYPE_UINT8);TYPE_TO_FIELDTYPE(int16_t, FIELDTYPE_INT16);TYPE_TO_FIELDTYPE(uint16_t, FIELDTYPE_UINT16);TYPE_TO_FIELDTYPE(int32_t, FIELDTYPE_INT32);TYPE_TO_FIELDTYPE(uint32_t, FIELDTYPE_UINT32);TYPE_TO_FIELDTYPE(int64_t, FIELDTYPE_INT64);TYPE_TO_FIELDTYPE(uint64_t, FIELDTYPE_UINT64);TYPE_TO_FIELDTYPE(float, FIELDTYPE_FLOAT);TYPE_TO_FIELDTYPE(double, FIELDTYPE_DOUBLE);

It is also relatively simple to use.TypeTraits<int>::FIELD_TYPEYou can getintEnumeration type corresponding to the typeFIELDTYPE_INT32

Summary

To sum up, there are two main advantages of traits programming skills.



Typical C programming example


Programmer recommends C ++ three-person discussion on books

HOST: bear Festival (transparent), editor of programmer magazine, member of C-View
Jia bin: Meng Yan (nightmare), a member of C-View at the Application Development Department of Lenovo handheld equipment department. He translated C ++ Standard Library together with Mr. Hou Jie
Jin Yin (devil), CTO of Shanghai Tianyu company, serialized a series of articles on "freedom and prosperity" in programmer

Transparency: "Which book does C ++ use to get started" is the most frequently asked question. But which one is the best entry book? It seems difficult to find the answer. C ++ Primer is too thick. Objective C ++ has a high requirement on readers. Essential C ++ is often criticized as "too light ".
In fact, it is: no silver bullet. It is impossible to learn C ++ from a book. A friend asked me how to learn C ++. I would suggest him go to the data structure book and use C ++ to do all the exercises, then go to Objective C ++. Myan often says that "a good habit should be developed in the early stages of learning", which I disagree.
I personally think that "Essential C ++" is suitable for teaching materials, "C ++ Primer" is suitable for reference books, and "Objective C ++" is suitable for extracurricular reading books.

Devil: I regret buying C ++ Primer. From my personal point of view, its function utility is basically The same as The C ++ Programming Language. Of course, it is quite good for beginners. However, C ++ Primer is too thick, which leads to extremely inconvenient reading, and system learning takes a long time. For the current fast-food era, there are indeed many unsuitable places, but they can be used as reference books for beginners. Now I lent it to someone else at the cost of a K3 CPU. I hope my colleague can enjoy some benefits.
If you already have C basics, I suggest you read Chinese books, such as Qian Neng's C ++ University tutorial (second edition). (If there is no C Foundation, check tan haoqiang's C language ). This book is quite clear about C. There are many exercises worth doing, especially the last two parts of struct and union. Some of these algorithms are relatively slow and cumbersome (such as tree and linked list Traversal Algorithms). You can try to modify these examples as a summary test of the C language.

Nightmare: This question reminds me of the situation before year 45. Today, most people who know C ++ have learned C ++ since those years. At that time, there was no brand concept at all. Find a C ++ book from the bookstore. If you still understand it, buy it. I remember that Professor Wan Yanyan, Zhang Guofeng, and Professor Mai zhongfan received high praise. My first book, C ++, was a book by Greg Perry. Today I think of it as a C language tutorial under the C ++ flag. One of the books most useful to me is a book published by the National Defense Science and Technology Press. The title of the book cannot be remembered. The author is Stephen breja.
Transparency: I still remember that I have criticized a C ++ book before. It was issued by Beihang, and the entire book has never seen the class keyword. That book only introduces the usage of the C language and iostream library, and it cannot be regarded as C ++. At that time, I often recommended a C ++ tutorial from the Electronic Science and Technology University. That book is not a big problem until today. The only drawback is that many things are outdated due to its long history. For a technical book, "Outdated" is the most unacceptable.
In general, the people who used C ++ at that time were "blind ". However, this is also advantageous because it can clearly understand many details of C ++, which will be easier to understand when you see classic books in the future. Of course, the disadvantage is that the concept is unclear, I don't even know what is the difference between C ++ and Visual C ++ and Borland C ++.

Nightmare: during the 1990s s, most people actually had a similar understanding of C ++. At first, it was equivalent to Borland C ++, and later it was equivalent to Visual C ++ and MFC. So in general, books under the banner of BC and VC sell well, people ...... The Rest Of The full text>

In C ++, what keywords does new represent?

"New" is a key word of C ++. It also has many topics about the new operator, because it is indeed complicated and mysterious, next, I will summarize the new-related content that I have learned.

New Process
When we use the keyword new to dynamically create an object on the stack, it actually does three things: getting a piece of memory space, calling constructors, and returning the correct pointer, of course, if we create A simple type variable, the second step is omitted. If we define the following Class:
Class
{
Int I;
Public:
A (int _ I): I (_ I * _ I ){}
Void Say () {printf (\ "I = % d \ n \", I );}
};
// Call new:
A * pa = new A (3 );
The above process of dynamically creating an object is roughly equivalent to the following three statements (only in general ):
A * pa = (A *) malloc (sizeof ());
Pa-> A: A (3 );
Return pa;
Although from the effect perspective, these three sentences also get A valid pointer pa pointing to the object on the stack, but the difference is that when malloc fails, it will not call the allocation memory failure handler new_handler, but use new, so we should try to use new unless there are some special requirements
Three new forms
So far, the new mentioned in this Article refers to "new operator" or "new expression", but in fact, when we mention new in C ++, it may at least represent the following three meanings: new operator, operator new, placement new
New operator is the new method we usually use. Its behavior is the three steps mentioned above. We cannot change it, but it is specific to the behavior in a step, if it does not meet our specific requirements, we may change it. In the three steps, the last step is simply to convert the pointer type. There is nothing to say, in addition, this conversion is not required in the compiled code. It's just a human understanding, but there are some content in the first two steps.
The first step of new operator to allocate memory is actually done by calling operator new. Here, new is actually the same operator as addition, subtraction, multiplication, division, therefore, operator new, which can be reloaded, first calls the memory allocation code by default to get a space on the heap. If it succeeds, it returns. If it fails, it calls a new_hander instead, repeat the previous process. If we are not satisfied with this process, we can reload operator new to set the expected behavior, for example:
Class
{
Public:
Void * operator new (size_t size)
{
Printf (\ "operator new called \ n \");
Return: operator new (size );
}
};

A * a = new ();
Here, operator new calls the original global new to achieve a global output of operator new before memory allocation can also be overloaded, but in this way, we can no longer recursively use new to allocate memory, but we can only use malloc:
Void * operator new (size_t size)
{
Printf (\ "global new \ n \");
Return malloc (size );
}
Correspondingly, delete also includes delete operator and operator delete... the remaining full text>

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.