STL source code analysis-Implementation of extraction programming (traits) Technology

Source: Internet
Author: User
Tags traits

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 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:

  1. Containers, including sequential containers (vector,list) And associated containers (map,set)
  2. Algorithm, function templates for various operations on containers (count,count_if)
  3. The iterator serves as a bridge between algorithms and containers, allowing algorithms to develop independently of containers.

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; 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 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 (struct, uint8_t) struct (fieldtype_int16, int16_t) values (cost, uint16_t) values (fieldtype_int32, int32_t) values (fieldtype_uint32, uint32_t) values (cost, int64_t) values (cost, float) variable_type_traits_helper (fieldtype_double, double) the macro-defined implementation method is used to avoid code duplication. 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 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.

  1. You can upgrade the judgment by using "Features" to the compilation level, rather than the runtime. This improves the performance.
  2. Universal implementation and data decoupling can be achieved


STL source code analysis-Implementation of extraction programming (traits) Technology

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.