C + + template--template Metaprogram (ix)

Source: Internet
Author: User
Tags square root

Metaprogramming contains the meaning of "programming a program". In other words, the programming system will execute the code we write to generate new code that truly implements what we expect. In general, the concept of metaprogramming implies a characteristic of reflection: the Metaprogramminig component is only part of the program, and it generates only a subset of the code or program.

The purpose of using metaprogramming is to achieve more functionality and to be less expensive (measured in terms of code size, maintenance overhead, etc.). On the other hand, the most important feature of metaprogramming is that some user-defined calculations can be performed during the program translation period. This usually brings benefits in terms of performance or interface simplicity, and even benefits both.

The metaprogramming concept in this article is dependent on the previous discussion of trait and type functions.

17.1 First instance of Metaprogram (recursive template)

The template instantiation mechanism is a basic recursive language mechanism that can be used to perform complex computations at compile time. Thus, the compile-time calculations that occur with template instantiation are often called template metaprogramming.

See a simple example: How to calculate a power of 3 at compile time

//meta/pow3.hpp#ifndef pow3_hpp#definePow3_hpp//Basic template for calculating the n-th square of 3Template <intN>classpow3{ Public:        enum{result =3* pow3<n-1>:: result};};//global specificity for ending recursionTemplate<>classpow3<0>{     Public:        enum{return=1 };};#endif      //pow3_hpp

Here the,pow3<> template (including its specificity) is referred to as a templated metaprogramming. It describes calculations that can be evaluated during the translation period (compile time), which is part of the template instantiation process.

17.2 enumeration values and static constants

In the original C + + compiler, within the class declaration, the enumeration value is the only way to declare "true constant Value" (also known as a constant expression). However, the standardized process for C + + now introduces the concept of static constant initialization within a class. We can modify the above example as follows:

//meta/pow3b.hpp#ifndef pow3_hpp#definePow3_hpp//Basic template for calculating the n-th square of 3Template <intN>classpow3{ Public:        Static int Constresult =3* pow3<n-1>: : Result;};//global specificity for ending recursionTemplate<>classpow3<0>{     Public:        Static int Constresult =1;};#endif      //pow3_hpp

In the new example we use static constant members instead of enumeration values. However, there is one drawback to this version: static member variables can only be left-valued. So, if you have a declaration like this:

void foo (intconst&);

And you pass in the result of the last Metaprogram, namely:

Foo (pow3<7>::result);

The compiler will have to pass the address of the Pow3<7>::result, which forces the compiler to instantiate the definition of the static member and allocate memory for that definition. As a result, the calculation will no longer be limited to the full "compile-time" effect. However, the enumeration values are not lvalue (that is, they do not have an address). Therefore, when you pass an enumeration value by reference, it does not use any static memory, as if it were passed as a literal constant to the computed value. So, for all the examples below, we use enumeration values instead of static constants.

17.3 Second Example: calculating the square root

//meta/sqrt1.hpp#ifndef sqrt_hpp#defineSqrt_hpp//basic template for calculating sqrt (N)Template <intNintLO =0,intHI = n>classsqrt{//Calculate Midpoint    enum{mid = (LO + HI +1) /2}; //find a smaller result with two points    enum{return= (n<mid*mid)? Sqrt<n, LO, mid-1>::result:sqrt<n, Mid, hi>:: result};};//local specificity, suitable for lo equals hitemplate<intNintM>classSqrt<n, M, m>{     Public:        enum{result =M};};#endif    //sqrt_hpp

Now consider the time when the compiler is trying to evaluate the following expression:

(<=8*8)? sqrt<1>::result:Sqrt<9;:: Result

At this point, the compiler instantiates the template on either side of the "?:" operator, which results in a large number of instantiations, approximately twice times the total number of N. This is not what we expect, because template instantiation is often a costly process for most compilers, especially for memory overhead. So instead of using the "?:" operator, we use the IfThenElse template we explained in the previous XXXXX blog:

//meta/sqrt2.hpp#include"ifthenelse.hpp"//Basic template for primary recursive stepsTemplate <intNintLI {0,intHI = n>classsqrt{//Calculate Midpoint    enum{mid = (LO + HI +1) /2}; //find a smaller result with two pointstypedef typename ifthenelse< (N<mid*mid), Sqrt<n, LO, mid-1, Sqrt<n, Mid, hi> >:: Resultt subt; enum{result =subt::result};};//local specificity, suitable for lo equals hitemplate<intNintS>classSqrt<n, S, s>{     Public:        enum{result =S};};

You can think of IfThenElse as a simple device (actually a template) that selects one of two types based on the value of a given Boolean constant. Remember: Defining a typedef for a class template instance does not cause the C + + compiler to instantiate the entity for that instance.

17.4 Using inductive variables

See Books, not notes

17.5 computational Integrity

Pow3<> and sqrt These two examples illustrate: a template Metaprogram can contain the following parts:

(1) State variables: That is, template parameters.

(2) Iterative construction: by recursion

(3) Path selection: By using conditional expressions or special

(4) Integer (that is, the value inside the enumeration should be an integer) algorithm

Template instantiation typically consumes huge compiler resources, and extended recursive instantiation can quickly degrade the compiler's efficiency and even consume all available resources.

The C + + standard recommends recursive instantiation of up to 17 layers, but it is easy to exceed this limit in real-world development. In some cases, however, Metaprogram is an irreplaceable tool for achieving efficient templates.

17.6 recursive instantiation and recursive template arguments

In this section, we present an example that shows that when using recursive template arguments, the compiler saves a mangled name for each type, which can become very large. Therefore, in cases where other conditions are the same, we still (tend to) avoid using recursive nested instantiation in template arguments when the organization is recursively instantiated.

17.7 using Metaprogram to expand loops This is a useful application for this blog post to expand the loop of numerical calculations:

 //  meta/loop1.hpp   #ifndef LOOP1. HPP   #define  LOOP1. Hpptemplate  <typename t>inline T dot_ Product ( int  Dim, t* A, T* b) {T result = T ();  for  (int  i = 0 ; I < Dim;    ++i) {result  + = A[i]*b[i];  return   result;}   #endif  //  LOOP1. HPP  

The problem with the above program is that, for many iterations, the compiler usually optimizes this loop (that is, iteration), and in this case, the optimization has a negative effect (why?). )。

If the library components that are designed to perform million-point multiplication calculations are useful, the difference can be significant. Template metaprogramming has solved this problem for us. The program is modified as follows:

//meta/loop2.hpp#ifndef LOOP2. HPP#defineLOOP2. HPP//Basic TemplatesTemplate <intDIM, TypeName T>classdotproduct{ Public:        StaticT result (t* A, t*b) {            return*a * *b + dotproduct<dim-1, T>::result (A +1, B +1); }};//local specificity as an end condition: The case of a unary vectorTemplate <typename t>classdotproduct<1, t>{     Public:        StaticT result (t* A, t*b) {            return*a * *b; }};//Auxiliary FunctionsTemplate <intDIM, TypeName T>inline T dot_product (t* A, t*b) {    returnDotproduct<dim, t>:: Result (A, b);}#endif //LOOP2. HPP

Can be called as follows:

dot_product<3> (a, b);

This expression instantiates an auxiliary function template, which is called directly inside the function template:

dotproduct<3int>::result (A, b);      // template arguments are: non-type template parameters, which are deduced from function template arguments

C + + template--template Metaprogram (ix)

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.