Turn: C ++ template element programming

xiaoxiao2021-03-05  29

C template meta-programming Author: glory Submitted by: eastvc Date: 2003-12-14 19:50:43 original source: http: //www.royaloo.com/articles/articles_2003/Metaprogramming.htm

Abstract This article describes the origin, concepts, and mechanisms of template programming technology, and introduces the application of template element programming technology in the BLITZ and LOKI libraries. Keyword compilation period Calculation Template Programming Blitz Loki Introduction In 1994, the C Standards Committee presented a code that can generate a current number. The special number of this code is that the current number is generated in the compile period rather than the time of operation, and all the numbers between the two to a set value in the middle of the compiler: // prime number computation by Erwin Unruh Template Struct D {D (void *); operator int ();}; template struct is_prime {enum {prim = (p% i) && is_prime <(i> 2 ? p: 0), i -1> :: prim};}; template a; enum {prim = is_prime :: prim}; Void f () {d d = prim;}}; struct is_prime <0,0> {enum {prim = 1};}; struct is_prime <0, 1> {enum {prim = 1}; Struct prime_print <2> {enum {prim = 1}; void f () {d <2> d = prim;}}; #ifndef last #define last 10 #ndif main () {prime_print a;} class Template D has only one parameter of a VOID * constructor, and only 0 can be legally converted to void *. In 1994, Erwin Unruh compiled an error message using the MetaWare compiler (and other information, short, they were deleted): | Type `enum {} 'can't be converted to TXPE` D <2>' (" Primes.cpp ", L2 / C25). | Type` Enum {} 'can't be converted to TXPE `D <3>' (" Primes.cpp ", L2 / C25). | Type` Enum {} 'CAN 'T be converted to TXPE `D <5>' (" Primes.cpp ", L2 / C25). | Type` Enum {} 'can't be converted to TXPE `D <7>' (" primes.cpp " , L2 / C25). Today, the above code is no longer a legal C program.

The following is the revision given by Erwin Unruh, which can compile the standard C compiler today: // prime number computation by Erwin Unruh Template Struct D {D (void *); operator int () ;}; Template 2? P: 0), i-1> :: PRIM};}; template struct prime_print {prime_print a; enum {prim = is_prime :: prim}; void f () {d d = prim 1: 0; AF ();}}; Template <> struct is_prime <0,0> {enum {prim = 1};}; template <> struct is_prime <0, 1> {enum {prim = 1}; }; Templa <> struct prime_print <1> {enum {prim = 0}; void f () {d <1> d = prim? 1: 0;};}; #ifndef last #define last 18 #ENDIF MAIN ) {Prime_print a; AF ();} When compiling this program in GNU C (MingW Special) 3.2, the compiler will give the following error information (and other information, short, they are deleted) : Unruh.cpp: 12: Initializing Argument 1 of `D :: d (void *) [with int i = 17] 'unruh.cpp: 12: Initializing Argument 1 of` D :: D (void *) [with int i = 13] 'unruh.cpp: 12: Initializing argument 1 of `D :: d (void *) [with int i = 11]' u Nruh.cpp: 12: Initializing Argument 1 of `D :: d (void *) [with int i = 7] 'unruh.cpp: 12: Initializing Argument 1 of` D :: D (void * [with int i = 5] 'unruh.cpp: 12: Initializing Argument 1 of `D :: d (void *) [with int i = 3]' unruh.cpp: 12: Initializing Argument 1 of `D :: D (void *) [with int i = 2] 'This example shows that you can use the template instantiation mechanism to perform some calculations. This compile period computing technique performed by template is called a template element programming.

A Template Metaprogramming analog Module Programming (Template Multi-program "programming" is a "program metaprogram", which can be edged ",") ". That is, we give the code generation rules, the compiler explains these rules in the compile period and generates new code to implement our expected functionality. Erwin Unruh's classic code did not execute, it only outputs the intermediate calculation result in a manner that compiles error information. Let's take a look at a template programming example - calculate the specified for the given integer: // xy.h // Original touch board Template class xy ​​{public: enum {result_ = base * XY :: result_};}; // Terminal Template for end recursive Template class xy ​​ {public: enum {result_ = 1}; The template element programming technology is in the recursive template instantiation. The first template implements a normal recursive rule. When using a pair of integers to instantiate the template, the template XY needs to calculate its Result_, and multiplied the result of in the same template by X I.e. The second template is a localized version for ending recursive. Let's see what happened when using this template to calculate 5 ^ 4 (by instant XY <5, 4>): // xytest.cpp # include #include "xy.h" int main () { Std :: cout << "x ^ y <5, 4> :: result_ =" << xy <5, 4> :: result_;} First, the compiler instantiate XY <5, 4>, its Result_ For 5 * xy <5, 3> :: result_, in this way, it is necessary to instantiate the same template for <5, 3>, and the latter is instantiated XY <5, 2> ... when instantiation to XY < 5, 0>, the value of Result_ is calculated to be 1, and the recursive ends. Recursive template instantiated depth and end conditions can be imagined, if we instantiate the class template XY with a very large y value, it will definitely take up a lot of compiler resources or even quickly exhaust the available resources (before calculating the result overflow) Therefore, in practice, we should use template programming technology in practice. Although the minimum instantiation depth of the C standard recommendation is only 17 layers, most compilers can handle at least dozens of layers, some compilers allow instantiation to hundreds of layers, more than thousands of layers until resources are exhausted .

What will the situation when we take the XY template local specialization? // xy2.h // Original touch board Template class xy ​​{public: enum {result_ = base * xy :: result_};}; test program constant: / / xytest2.cpp #include #include "xy2.h" int main () {std :: cout << "x ^ y <5, 4> :: result_ =" << xy <5, 4>: : result_;} Perform the following compile command: C: /> G -c xytest2.cpp You will see that the recursive instantiation will continue until the limit of the compiler. The default instantiated limit of GNU C (Mingw Special) 3.2 is 500 layers, you can also manually adjust the instantiated depth: C: /> G -ftemplate-depth-3400 -c xytest2.cpp act, G 3.2 allowed template The instantiated limit is still larger (my test results are not more than 3450 layers). Therefore, when using template element programming technology, we always give the primitive version of the original template (local specialty version or completely transmissions or both) to instantiate the recursive template. Using Template Programming Techniques Unplug the earliest actual application of cyclic template meta programming technology is the decomposition of numerical calculations.

For example, the common method for summing an array is: // Sumarray.hTemplate Inline T Sum_Array (int Dim, T * a) {t result = t (); for (int i = 0; I Class Sumarray {public: static t result (t * a) {return a [0] SUMARRAY :: Result (A 1);}}; // Terminal Terminal Terminal Template Class Sumarray <1, T> {Public: Static T Result (t * a) {Return A [0];}}; Usage is as follows: // SumaRraytest2.cpp # include #include "sumarray2.h" int main () {Int a [6] = {1, 2, 3, 4, 5, 6}; std :: cout << "SUMARRAY <6> (a) = << Sumarray <6, int> :: result (a);} When we calculate SUMARRAY <6, INT> :: Result (a), the instantiation process is as follows: SUMARRAY <6, INT> :: Result (A ) = a [0] sumvector <5, int> :: result (a 1) = a [0] a [1] sumvector <4, int> :: result (A 2) = a [0 ] a [1] a [2] sumvector <3, int> :: result (a 3) = a [0] a [1] a [2] a [3] Sumvector <2 , int> :: result (A 4) = a [0] a [1] a [2] a [3] a [4] su MVector <1, ​​int> :: result (A 5) = a [0] a [1] a [2] a [3] a [4] a [5] can be seen, the cycle is deployed A [0] a [1] a [2] a [3] a [4] a [5]. This straightforward deployment is almost always more efficient than the cycle. Perhaps take an array of 6 million elements to illustrate the advantages of cyclic ankills more convincing. Generating such an array is easy, interested, you may wish to test, compare it. Template Programming Application BLITZ in the numerical computing library "Fast, Lightning" (this is the literal meaning of BliTz), and is inseparable from the credit of the template program. BLITZ uses the meta-programming technology, you can get to these file source code:

Dot.hmatassign.hmatmatmatmatmatvec.hmetaprog.h product.h Sum.h VECASSIGN.H Let's take a look at the template program in the Blitz library Dot.h file: Template

Class _bz_meta_vectordot {

PUBLIC:

ENUM {loopflag = (i

Template

Static inline bz_promote (_bz_typename t_expr1 :: t_numtype, _bz_typename t_expr2 :: t_numtype)

f (const t_expr1 & a, const t_expr2 & b)

{

RETURN A [I] * B [i] _bz_meta_vectordot :: F (a, b);

}

Template

Static inline bz_promote (_bz_typename t_expr1 :: t_numtype, _bz_typename t_expr2 :: t_numtype)

F_Value_ref (T_EXPR1 A, Const T_EXPR2 & B)

{

RETURN A [I] * B [i] _bz_meta_vectordot :: F (a, b);

}

Template

Static inline bz_promote (_bz_typename t_expr1 :: t_numtype, _bz_typename t_expr2 :: t_numtype)

f_ref_value (const t_expr1 & a, t_expr2 b)

{

RETURN A [I] * B [i] _bz_meta_vectordot :: F (a, b);

}

Template

Static Inline BZ_Promote (_BZ_TYPENAME T_EXPR1 :: T_NUMTYPE, P_NUMTYPE2)

Dotwithargs (const t_expr1 & a, p_numtype2 i1, p_numtype2 i2 = 0,

P_numtype2 i3 = 0, p_numtype2 i4 = 0, p_numtype2 i5 = 0, p_numtype2 i6 = 0,

P_numtype2 i7 = 0, p_numtype2 i8 = 0, p_numtype2 i9 = 0, p_numtype2 i10 = 0)

{

RETURN A [I] * i1 _bz_meta_vectordot :: dotwithargs

(A, I2, I3, I4, I5, I6, I7, I8, I9);

}

}

Template <>

Class _bz_meta_vectordot <0, 0> {

PUBLIC:

Template

Static inline _bz_meta_nulloprand f (const t_expr1 &, const t_expr2 &) {return_bz_meta_nulloperand ();

Template

Static inline _bz_meta_nullopernd

Dotwithargs (const t_expr1 & a, p_numtype2 i1, p_numtype2 i2 = 0,

P_numtype2 i3 = 0, p_numtype2 i4 = 0, p_numtype2 i5 = 0, p_numtype2 i6 = 0,

P_numtype2 i7 = 0, p_numtype2 i8 = 0, p_numtype2 i9 = 0, p_numtype2 i10 = 0)

{

Return _bz_meta_nulloperand ();

}

}

This code is much simpler than it looks. _bz_meta_vectorDot Template uses a temporary variable loopflag to store assessment results of each step, and use a fully transmissive version as a condition for recursive end. It should be noted that, like almost all of the programs, this temporary variable is played in the compile period and will be optimized from the run code.

Todd is the main author of the BLITZ numerical number library. This library (as well as MTL and Pooma, etc.) illustrations template programs can bring us more efficient numerical computing performance. Todd claims that BLITZ can be compared with the corresponding Fortran library.

Loki Base Library: Model of Mechanization Template Programming Technology

The value of the template element program is only in high performance value calculations? Not only that. The LOKI library is known for the C community in the pantage model. It is very secluded in the Typelist component. Typelist is an indispensable infrastructure that implements generic models such as Abstract Factory, Visitor.

Just like the C standard library component std :: list provides the operation of a set of values, Typelist can be used to manipulate a set of types, which is very simple (taken from the Loki library Typelist.h unit):

Template

Struct Typelist

{

Typedef t headad;

Typedef u tail;

}

Obviously, Typelist does not have any status, and does not define any operations only to carry type information, which is not intended to be instantiated, so any processing for TyPelist will inevitably occur in the compile period rather than the operation period.

TypeList can be expanded in unlimited because the template parameters can be any type (including other exclusions of the template). E.g:

TYPELIST >>>>

It is a Typelist containing three types of char, int, float.

According to the LOKI's convention, each Typelist must end with NULLTYPE. NULLTYPE effect is similar to "/ 0" of traditional C strings, which is declared in the NullType.h file of the Loki library:

Class NullType;

NullType only declares, no definition, because the Loki library will never need to create a NullType object.

Let's take a look at the indexof template program, which can find the location of a given type in a TypeList (from the Typelist.h unit of the Loki library): Template

Struct indexof;

Template

Struct Indexof

{

ENUM {Value = -1};

}

Template

Struct Indexof , T>

{

ENUM {Value = 0};

}

Template

Struct Indexof , t>

{

Private:

Enum {temp = indexof :: Value};

PUBLIC:

Enum {value = (TEMP == -1? -1: 1 TEMP)};

}

IndexOf provides an original template and three local specialization. The algorithm is very simple: if TLIST (is a Typelist) is a nulltype, the value is -1. If the head of TLIST is T, Value is 0. Otherwise, IndexOf is applied to the tail and T of the TLIST, and the evaluation result is placed in a temporary variable TEMP. If the TEMP is -1, the value is -1, otherwise Value is 1 TEMP.

In order to deepen your understanding of template programming technology used by Typelist, I stripped from the Loki library out of the following code, put in a TypelistLite.h file:

// TypelistLite.h // Declaration NullType

Class NullType;

// Typelist definition

Template

Struct Typelist

{

Typedef t headad;

Typedef u tail;

}

// Indexof definition // indexof original template

Template Struct Indexof;

/ / Local-specific version of NullType

Template

Struct Indexof

{

ENUM {Value = -1};

}

// For the "TLIST head is the local special version of the T" we want to find

Template

Struct Indexof , T>

{

ENUM {Value = 0};

}

// Treat part of the TLIST tail

Template

Struct Indexof , t>

{

Private:

Enum {temp = indexof :: Value};

PUBLIC:

Enum {value = (TEMP == -1? -1: 1 TEMP)};

}

The test procedure is as follows:

// TypelistLite_test.cpp # include

#include "typelistlite.h"

// Customize Type Royal

Class Royal {};

/ / Define a TyPelist with char, int, royal and float

TypedEf Typelist >>> CIRF;

int main ()

{

Std :: COUT << "Indexof :: Value =" << Indexof :: Value << "/ N";

Std :: COUT << "Indexof :: Value =" << Indexof :: Value << "/ n";

Std :: COUT << "Indexof :: Value =" << Indexof :: Value << "/ n";

}

The program output is as follows:

Indexof :: Value = 1

Indexof :: Value = 2

Indexof :: Value = -1

Conclusion

Template programming techniques are not all advantages. For example, when template program compiles, the code size generated by the programming program is more than the ordinary program, and usually this program is difficult than the conventional procedure. many. In addition, for some programmers, the algorithm may be a bit abstraction in a class template.

The cost of compiling time is exchanged for outstanding runtime performance. In general, a meaningful program is always over far exceeding the number of compilation times (or compile time). Bring better experiences for users of the program, or for higher performance, strict numerical values, which is worthy of programmers to pay such a price.

It is difficult to imagine template programming technology to become every normal for every ordinary programmer. In contrast, like Blitz and Loki, template programs should always be packaged inside the library. For users of the library, it should be transparent. The template program can (also) use as the kernel of conventional template code, for critical algorithms to achieve better performance, or to achieve special effects for special purposes.

Template element programming technology is officially unveiled in Todd Veldhuizen

Unsing C Template Metaprograms Paper. This article first published in May 1995

C Report Journal, Later, Stanley Lippman Editor

C gems is included in the book. The link to this article is given in the reference, which also describes many of the contents not described herein.

David Vandevoorde and Nicolai M. Josuttis

C Templates: The Complete Guide spends a whole chapter to introduce template programming technology, which is also the reference material of this article and should also be used as your supplementary reading materials.

Andrei Alexandrescu's genius book MODERN C Design: Generic Programming and Design Patterns Applied Chapter 3

Typelists has more detailed descriptions for Typelist.

references

1. David Vandevoorde, Nicolai M. Josuttis,

C Templates: The Complete Guide, Addison Wesley, 2002

Andrei Alexandrescu, Modern C Design: Generic Programming and Design Patterns Applied, Addison Wesley, 2001.3. Hou Jie Yu Chun Jing translated, "C Design New Thinking", Huazhong University of Science and Technology Press, 2003. . 4. Todd Veldhuizen, Template Metaprograms, http://osl.iu.edu/~tveldhui/papers/Template-Metaprograms/meta-art.html 5. Todd Veldhuizen, C templates as partial evaluation (PEPM99), http: / / 斯L.iu.edu/~tveldhui/papers/pepm99/. 6. Erwin unruh, prime number, http://www.erwin-unruh.de/primorig.html. 7. Erwin Unruh, Prime Numbers (primzahlen), http://www.erwin-unruh.de/prim.html. 8. Blitz , http://www.oonumerics.org/blitz. 9. loki, http://sourceforge.net/projects / loki-lib. 10. Pooma, http://www.pooma.com. 11. Mingw - minimalist gnu for windows, http://sourceforge.net/projects/mingw.

转载请注明原文地址:https://www.9cbs.com/read-35273.html

New Post(0)