Reading Notes Objective c ++ Item 48 learn about template metaprogramming and objective tiveitem

Source: Internet
Author: User

Reading Notes Objective c ++ Item 48 learn about template metaprogramming and objective tiveitem
1. What is TMP?

Template metaprogramming TMP) Is to implement template-Based C ++Program process, which can be executed during compilation. You can think about it: a template metaprogram is implemented in C ++ and can run in the C ++ compiler, its output-the C ++ source code snippet instantiated from the template-will be compiled as usual.

2. advantages of using TMP

If this doesn't affect you, it's because you don't have enough effort to think about it.

 

C ++ is not designed for template meta-programming, but since TMP was discovered in 1990, it has been proved to be very useful, in order to make it easier to use TMP, some extensions are added to the C ++ language and standard library. Yes, TMP is discovered, not invented. The TMP feature is introduced when the template is added to C ++. For some people, all they need to do is focus on how to use it in a smart and unexpected way.

TMP has two powerful powers.First, it makes some things easier.,That is to say, if noTMPThese tasks are difficult or impossible to achieve..Second, because the template metadata is stored inC ++Compile-time execution, which can move some work from runtime to compile-time. One result is some errors that can be found at runtime and can be found at the compilation stage. Another result is that the tmp c ++ program is more efficient in almost every aspect:Smaller execution bodies, shorter running time, and less memory requirements. (However, one consequence of moving work from runtime to compilation isCompilation Time increased. Programs using TMP may take longer time to compile than those without TMP .)

3. How to Use TMP? 3.1 re-analyze the instance in Item 47

Consider the pseudo code written for STL advance in Item 47. I have already bold the pseudocode:

 1 template<typename IterT, typename DistT> 2 void advance(IterT& iter, DistT d) 3 { 4 if (iter is a random access iterator) { 5  6 iter += d;                           // use iterator arithmetic 7  8 }                                        // for random access iters 9 10 else {                                11 12 13 if (d >= 0) { while (d--) ++iter; } // use iterative calls to14 else { while (d++) --iter; } // ++ or -- for other15 } // iterator categories16 }

 

We can use typeid to replace the pseudo code so that the program can be executed. This produces a "common" C ++ method-that is, the method that all work is carried out at runtime:

 1 template<typename IterT, typename DistT> 2 void advance(IterT& iter, DistT d) 3 { 4 if ( typeid(typename std::iterator_traits<IterT>::iterator_category) == 5 typeid(std::random_access_iterator_tag)) { 6  7 iter += d;                           // use iterator arithmetic 8  9 }                                        // for random access iters10 11 else {                               12 13 14 if (d >= 0) { while (d--) ++iter; } // use iterative calls to15 else { while (d++) --iter; } // ++ or -- for other16 } // iterator categories17 }

 

Item 47 points out that this typeid-based method is less efficient than trait, because by using this method, (1)The type test occurs at runtime rather than during compilation.(2)The code for executing the type test at runtime must be visible at runtime. In fact, this example shows why TMP is more efficient than a "common" C ++ program, because the traits method belongs to TMP. Remember, trait enables the type to be compiled if... Else operations are possible.

I have mentioned a few things that show that it is easier in TMP than in "normal" C ++, and Item 47 also provides an example of advance. Item 47 mentioned that the implementation of advance Based on typeid will cause compilation problems. See the following example:

1 std::list<int>::iterator iter;2 ...3 advance(iter, 10);               // move iter 10 elements forward;4 // won’t compile with above impl.

 

Consider the version of the advance generated by the above call. After replacing the template parameters IterT and DistT with iter and 10, we will get the following code:

 1 void advance(std::list<int>::iterator& iter, int d) 2 { 3 if (typeid(std::iterator_traits<std::list<int>::iterator>::iterator_category) == 4 typeid(std::random_access_iterator_tag)) { 5  6 iter += d; 7  8 // error! won’t compile 9 10 11 }12 else {13 if (d >= 0) { while (d--) ++iter; }14 else { while (d++) --iter; }15 }16 }

 

The problem is that the highlighted part uses the + = Statement. In this example, we use + = on list <int >:: iterator, but list <int >:: iterator is a bidirectional iterator (see Item 47 ), therefore, it does not support + =. Only the random access iterator supports + =. Now we know that the row + = will never be executed, because the typeid test executed for list <int>: iteraotr will never be true,However, the compiler has the responsibility to ensure that all source code is valid, even if it is not executedIf iter does not randomly access the iterator "iter + = d", it is invalid code. Compare it with the TMP solution based on tratis. The latter places the codes implemented for different types into different functions, the operations performed in each function are only for specific types.

3.2 TMP is completely Turing

TMP has been proven to be completely Turing-Complete, which means it is powerful enough to compute anything. With TMP, you can declare variables, execute loops, implement and call functions, and so on. However, these concepts seem very different from those corresponding to "normal" C ++. For example, if… In Item 47... The else condition is expressed in TMP by using the template and template features. But this is the TMP of the assembly-level. The TMP Library (for example, Boost MPL, see Item 55) provides more advanced syntaxes that won't be mistaken for "normal" C ++.

3.3 The cycle in TMP is implemented through Recursion

Let's take a look at how things work in TMP. TMP does not have the concept of a true loop, so the effect of a loop is achieved through recursion. (If recursion is mentioned, you will not be comfortable. You need to deal with it before getting into the TMP adventure. TMP is mainly a functional language. recursion is as important for functional languages as TV is to popular American cultures: they are inseparable .) Even recursion is not a common recursion, because the TMP loop does not involve recursive function calls and involves the recursive template instantiation (template instantiations ).

The "hello world" program of TMP calculates the factorial during compilation. It is not an exciting program, nor is it "hello world", but these two examples are helpful for introducing languages. TMP factorial calculation uses recursion to demonstrate the cycle. It also demonstrates how variables are created and used in TMP. See the following code:

 1 template<unsigned n>          // general case: the value of 2  3 struct Factorial {                   // Factorial<n> is n times the value 4  5  6 // of Factorial<n-1> 7 enum { value = n * Factorial<n-1>::value }; 8 }; 9 template<> // special case: the value of10 struct Factorial<0> { // Factorial<0> is 111 enum { value = 1 };12 };

 

Consider the previous template metaprogramming (actually only a single metadatabase Factorial). You can reference Factorial <n >:: value to obtain the value of factorial (n.

The code loop occurs when the template instance Factorial <n> references the template instance Factorial <n-1>. Like all recursion, there is a special case for Recursive termination. Here is the specific Factorial template <0>.

An instance of each Factorial template is a struct. Each struct uses enum hack (Item 2) to declare a TMP variable called value. Value holds the current Value of recursive calculation. If TMP has a real loop structure, the value is updated each time it is cyclically. Since TMP uses recursive template instances to replace loops, each instance will get a copy of its own value, and each copy will have a suitable value corresponding to the position in the loop.

You can use Facorial as follows:

1 int main()2 {3 std::cout << Factorial<5>::value; // prints 1204 5 std::cout << Factorial<10>::value;       // prints 36288006 7 }        

If you think this is cooler than ice cream, you have obtained the materials required by the template meta programmer. If templates and features, recursive instances, and enum hacks, and input such as Factorial <n-1>: value make you chilling, you are still a "common" C ++ programmer.

3.4 what can TMP do?

Of course, Factorial demonstrates the functions of TMP, just as the "hello world" program demonstrates the functions of any traditional programming language. To help you understand why TMP is worth understanding and what it can do, here are three examples:

  • Ensure that the dimenstmunit is correct. In scientific and engineering applications, it is necessary to combine the units (for example, quality, distance and time) correctly. It is wrong to assign a value to the variable indicating the speed, but there is no problem to assign a value to the variable by dividing the distance variable by the time variable. By using TMP, it is possible to ensure the correctness of all the sub-unit combinations in the Program (during compilation), regardless of the complexity of the calculation. (This is also an example of using TMP to detect early errors .) An interesting aspect of the usage of TMP is that it supports the score index. This requires that scores be simplified during compilation before the compiler can confirm. For example, the Unit time1/2 is the same as time4/8.
  • Optimize matrix operations. Item 21 explains that some functions (including operator *) must return new objects. The SquareMatrix class is introduced in Item 44. Consider the following code:

    1 typedef SquareMatrix<double, 10000> BigMatrix;2 BigMatrix m1, m2, m3, m4, m5; // create matrices and3 ... // give them values4 BigMatrix result = m1 * m2 * m3 * m4 * m5; // compute their product

    The "normal" method is used to calculate the result. There will be four calls to create a temporary matrice object. Each call is applied to the return value of the operator * Call. These independent multiplications generate four cycles on the matrix element. Using the TMP advanced template technology-expression template (expression templates), it is possible to eliminate temporary objects and merge loops, without modifying the above client code syntax. The last program uses less memory, and the running speed will be greatly improved.

  • Produce personalized design patterns. Such design patterns as policy patterns, observer patterns, and visitor patterns can be implemented in many ways. The template-based technology is called policy-based design. We can create a template that represents an independent design choice (choice or "decision ies, these templates can be combined in any way to generate personalized mode implementation. For example, this technology can be used to create templates that implement smart pointer behavior policies (ies). Using it, hundreds of different smart pointer types can be generated (during compilation. This technology has surpassed programming technology, such as design patterns and smart pointers, and has become the foundation of generative programming.
4. TMP Status Quo Analysis

TMP is not prepared for everyone. Because the syntax is not intuitive, The Supported tools are also weak. (For example, the debugger provided for template metaprogramming .) As a "unexpected" language, it was only recently discovered. Some TMP programming conventions are in the experimental stage. However, the efficiency improvements brought about by moving the work from runtime to the compilation phase bring a deep impression on the ability to express some behaviors (difficult or impossible to achieve at runtime) it is also very attractive.

The support for TMP is on the rise. It is very likely that the next version of C ++ supports the display. TR1 supports Item 54 ). Books on this topic have begun, and more TMP information is available on the Internet. TMP may never become the mainstream, but for some programmers-especially the library implementers-It is almost inevitable that it will become the main means.

5. Summary
  • Template metaprogramming can move work from runtime to compilation, so that errors can be detected earlier and runtime performance can be improved.
  • The combination of TMP based on policy choices can be used to generate personalized code, and can also be used to prevent generating inappropriate code for a specific type.

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.