The traits technology is widely used in STL, through which you can easily extract the features of an object. It is also used in STL to optimize the performance. For example, if an object is a POD object (Plain Old Data), it can be directly copied through functions such as memcpy during the copy process, instead of calling the copy constructor or operator =.
Let's take a look at iterator, the most basic object in STL.
The code above shows that the value_type, size_type, difference_type, pointer, reference, const_pointer, const_reference, AND self types must be defined for each iterator.
Template <typename T, typename Size = size_t, typename Difference = ptrdiff_t>
Struct iterator
{
Typedef T value_type;
Typedef Difference difference_type;
Typedef T * pointer;
Typedef T & reference;
Typedef const T * const_pointer;
Typedef const T & const_reference;
Typedef iterator <T, Size, Difference> self;
};
Template <typename T, typename Size = size_t, typename Difference = ptrdiff_t>
Struct const_iterator: public iterator <T>
{
}; 1. value_type
Value_type indicates the type of value saved by the iterator.
Ii. difference_type
Difference_type is used to indicate the distance type between two iterators www.2cto.com
Iii. pointer, reference, const_pointer, const_reference
Pointer, reference, pointer constant, and reference constant respectively.
Iv. self
Self is the type of the iterator.
Next let's take a look at iterator_traits. iterator_traits is mainly used to extract the iterator value type and so on.
Template <typename Iterator>
Struct iterator_traits
{
Typedef typename Iterator: value_type;
Typedef typename Iterator: difference_type;
Typedef typename Iterator: pointer;
Typedef typename Iterator: reference;
Typedef typename Iterator: const_pointer;
Typedef typename Iterator: const_reference;
Typedef typename Iterator: self self_type;
};
Here, we can tell you in advance that vector is used as a container internally as an iterator. How can we extract its value type?
The answer is simple and special, so we will make two T * and const T * special cases for iterator_traits.
Template <typename T>
Struct iterator_traits <T *>
{
Typedef T value_type;
Typedef ptrdiff_t difference_type;
Typedef T * pointer;
Typedef T & reference;
Typedef const T * const_pointer;
Typedef const T & const_reference;
Typedef T * self_type;
};
Template <typename T>
Struct iterator_traits <const T *>
{
Typedef T value_type;
Typedef ptrdiff_t difference_type;
Typedef T * pointer;
Typedef T & reference;
Typedef const T * const_pointer;
Typedef const T & const_reference;
Typedef const T * self_type;
}; So far, we can use iterator_traits to extract the value types of each iterator.
As mentioned earlier, traits can extract some object features to improve code efficiency. In fact, traits can be used to extract whether an object is a POD object. For a POD object, we should not use its copy constructor or operator = When copying it, memcpy is more efficient.
Next let's take a look at _ type_traits
Struct _ true_type
{
};
Struct _ false_type
{
};
Template <typename I>
Struct _ type_traits
{
Typedef _ false_type has_default_construct;
Typedef _ false_type has_copy_construct;
Typedef _ false_type has_assign_operator;
Typedef _ false_type has_destruct;
Typedef _ false_type is_POD;
}; It must be mentioned that _ true_type and _ false_type are used to indicate whether this feature exists.
So how can we extract the features of basic types such as int and char?
The answer is still a special case. The Code will not be posted here. The detailed address of the complete code will be provided at the end of this article.
Finally, we use a hash_destruct function to obtain whether there is a destructor of this type.
Template <typename T>
Inline auto has_destruct (const T &)-> decltype (static_cast <__type_traits <T >:: has_destruct *> (0 ))
{
Return static_cast <typename _ type_traits <T >:: has_destruct *> (0 );
}
Template <typename T>
Inline auto has_destruct (T *)-> decltype (static_cast <__type_traits <T >:: has_destruct *> (0 ))
{
Static_assert (false, "Please use const T & not T *");
Return static_cast <typename _ type_traits <T >:: has_destruct *> (0 );
}
Template <typename T>
Inline auto has_destruct (const T *)-> decltype (static_cast <__type_traits <T >:: has_destruct *> (0 ))
{
Static_assert (false, "Please use const T & not const T *");
Return static_cast <typename _ type_traits <T >:: has_destruct *> (0 );
} I have to mention that C ++ 0x is indeed very powerful. You can use the form parameter to determine the type of the returned value, in this way, we can extract the has_destruct domain of this type as _ true_type or _ false_type.
Finally, let's take a look at the construct and destruct code. In STL, the memory allocation and construction of objects are separated. for basic objects such as int and char, we do not need to call the Destructor during the analysis.
The following describes the implementation of construct and destruct.
Template <typename T1, typename T2>
Inline void construct (T1 * p, const T2 & value)
{
New (p) T1 (value );
}
Template <typename T>
Inline void destruct (T * p, _ true_type *)
{
P-> ~ T ();
}
Template <typename T>
Inline void destruct (T *, _ false_type *)
{
}
Template <typename ForwardIterator>
Inline void destruct (ForwardIterator first, ForwardIterator last)
{
While (first! = Last)
{
Destruct (first, has_destruct (* first ));
++ First;
}
}
Lwch