Preface: Bishi in the open Source Library to do the program, but the source looked very faint (at that time the tutor told me this is the template meta-programming, you can not care too much), recently built the wheel when I want to learn STL source code, but it is the same feeling, roughly understand what he does to do, but do not know the mechanism inside. So began to learn "C + + template meta-programming", read the second chapter on some things suddenly enlightened.
PS: The book is also a bit old, c++11 standard has not come out, the main use of the boost library.
Traits (characteristic)
To get to the point, the name of the suffix traits can often be seen in the STL, such as the std::string, which is often used, the first parameter of the class template basic_string the chart is instantiated as Char. Accordingly, the string template class that is used to represent a wide byte is wstring,chart to wchar_t.
Template < class CharT, class traits = Char_traits<chart>, //Basic_string::traits_type class Alloc = allocator<chart> //Basic_string::allocator_type > class basic_string;typedef basic_string <char, Char_traits<char>, allocator<char> > string;
According to the template declaration, 3 template parameters, the chart represents the holding character type (Char type), Alloc is the instantiation of the allocator<t>, usually new is a one-time allocation of memory and then in memory constructs the T type element, Allocator<t> separates the two processes, you can allocate a contiguous memory space, the equivalent of a memory pool, and then directly on the above constructs the T type element, does not need to destroy the element, the memory space is not released, you can re-construct the new element on it. This eliminates the process of reallocating space and constructing elements each time. A little bit like the Malloc/free package for C. (not carefully studied, not to Xiang)
The 2nd template parameter traits is the instantiation of the char_traits template parameter for the chart
Template<class _elem> struct char_traits : public _char_traits<_elem, long> { // Properties of a string or stream unknown element };
You can find that char_traits inherits from the template class instantiated by _char_traits and can provide extensions. There is no extension, basically can be char_traits equivalent template class in _char_traits<_elem, long>
Template<class _elem, class _int_type> struct _char_traits { //properties of a string or stream Element typedef _elem CHAR_TYPE; typedef _int_type INT_TYPE; typedef streampos POS_TYPE; typedef streamoff OFF_TYPE; typedef _mbstatet STATE_TYPE; // ... }
After omitting the static method, you can see that there are 5 typedef before this. In C + +, the inside of a class can define a type alias with a TypeDef, which can be used just like a static member.
This means that you can use the template class _char_traits<_elem, _int_type>::char_type to get the type name. In conjunction with this, Char_traits inherits from the template class, so you can use Char_traits::char_type to get the type name. It can be found that inheriting a template class is a bit like instantiating a template class to get type aliases (such as TypeDef std::map<int, std::string> mapintstr;), which greatly reduces the pressure on the keyboard input.
Back, Std::basic_string's 2nd template parameter traits is instantiated by the character type chart as a template parameter (_elem) char_traits
That is, in std::basic_string, the type can be obtained directly through the template parameter traits. For example, Traits::char_type is equivalent to chart.
The question is: why should I specifically set the template parameters to a template?
The example of an iterator traits directly borrowed from a book is similar to Char_traits.
When we need to swap iterators (the function is the value that the interchange iterator points to)
Template <class FwIt1, class fwit2> void Iter_swap (FwIt1 i1, FwIt2 i2) { typename Fwit1::value_type TMP = *I1; *i1 = *i2; *I2 = tmp; }
There is a problem with this implementation, Fwit must be like char_traits, inside there is a typedef to take a certain type of individual named Value_type. If you implement a new iterator yourself, you can always add a corresponding typedef to each class template in accordance with this standard.
The problem is that, without talking about whether other class templates implement TypeDef, the pointers are incompatible in Iter_swap. So you need to add something like an adapter, so that the pointer can also be plugged into the iter_swap.
Now we write a iterator_traits as an adapter.
Template <class iter> struct iterator_traits { typedef typename Iter::value_type value_type; };
The class has only one line of code for the type alias definition, so that Iterator_traits<iter>::value_type is equivalent to Iter::value_type, and the type instantiates a class template instead of the type itself.
A good feature of the C + + template is the exception (specialization), when the template parameter has a particular type, choose to instantiate "exception type" instead of the generic template. For example, the internal implementation of std::vector<bool> and other general std::vector<t> is not the same.
After you have made a special exception to the pointer type
Template <class t> struct iterator_traits<t*> { typedef typename T value_type; };
If you instantiate a iterator_traits with a pointer type, you will choose this to instantiate instead of the previous generic form. (Choose which template instantiation is not detailed here, "C + + Primer" has relevant instructions)
The original Iter_swap became
Template <class FwIt1, class fwit2> void Iter_swap (FwIt1 i1, FwIt2 i2) { // TypeName Fwit1::value _type tmp = *I1; TypeName iterator_traits<fwit1>::value_type tmp = *I1; *i1 = *i2; *I2 = tmp; }
As can be seen, the template parameter on the template is the role of the adapter, in the class template in a more general way to obtain type information, equivalent to a system within a unified standard.
The C + + standard library has implemented iterator_traits, and only iterators can be used as template parameters, because only the iterator class implements those specific typedef. In addition, Iterator_traits also has an exception for pointer types. If you use a container as a template parameter, you will get an error (such as which typedef is not implemented).
Back to the original question: What is template meta programming? What is the relationship between using this traits technique and template metaprogramming?
Briefly explaining meta-programming (meta-programming), meta-programming is similar to an interpreter, such as C + +, which generates a compilation of the resulting machine code to run the computer.
The template meta-programming (TMP) is in the C + + system, template instantiation will become a new code, but the new code is still C + + code, the advantages of the template as its name, a set of different parameters can be described as a group of similar types of functions and different classes or functions. For example, std::vector<int> and std::vector<float> are two types, but they have a common approach.
The instantiation of a template occurs during compilation, which is the root cause of C + + tmp, and the things that can be done during compilation do not need to be done during the run time, although the compilation takes longer, but will result in an increase in operational efficiency.
The first chapter of C + + template meta-programming is given directly, using template meta-programming to convert the binary number to decimal number, and the instantiated value is computed at compile time.
Template <unsigned long n>struct binary{ static unsigned const value = Binary<n/10>::value << 1 | N% 10;};/ /Special template <>struct binary<0>{ static unsigned const VALUE = 0;};
The idea is that a short class template code is equivalent to a very long, long, constant expression (determined during compilation), and using Binary<110010>::value at run time is equivalent to using a constant expression directly (as an assignment, an argument, and so on). And if the traditional method of writing a function to calculate, is at run time to calculate.
And the type is essentially the same as the value, just as we have a typedef in the class, and using aliases outside of the class is the same as using static members. Template meta-programming is not only to do this numerical operation, but also to do type operations, the front spent a large number of references to traits is a classic example.
Initial knowledge of C + + template meta-programming (Templates Mega programming)