Métaprogrammation with owners
The Métaprogrammation with owners is a technique of programming in which the owners are used so that the Compilateur, during the compilation of the code, carries out a program. These programs can generate constants or structures of data. This technique is used mainly in the computer programming language C++.
Calculation of constants
The simple example of calculation of factorial with recursion illustrates well what is the " programming at the time of the compilation".In C++, a function Factorielle can be written recursively as follows:
int factorial (unsigned int N)
{
yew (N == 0)
return 1;
return N * factorial (N - 1);
}
// factorial (4) == (4 * 3 * 2 * 1) == 24
// factorial (0) == 0! == 1
By using the metaprogrammation with owners, one can write:
templatestruct Factorial { enum {value = NR * Factorielle :: value}; }; template <> struct Factorielle<0> { enum {value = 1}; };
// Factorielle<4>:: value == 24 // Factorielle<0>:: value == 1
The solution of the metaprogrammation with owners uses the specialization of owner to finish recursion. Although these two solutions are similar, in the second case, Factorielle<4>:: valeur is calculated during compilation. That implies that Factorielle< X >:: valeur can ête used only if X is known during compilation, i.e. if X is a constant or the résulat of a call to sizeof () .
In D, the owner factorial would resemble:
template Factorial (unsigned int N) { static if (N == 1) const Factorial = 1; else const Factorial = N * Factorial! (n-1); } // Factorial! (4) == 24
The metaprogrammation with owners has practical uses in spite of its awkward appearance. It can be used to create classes vector with N dimensions when N is known with compilation. The advantage compared to a vector with N dimensions traditional is that the loops can be unrolled, which produces a very optimized code.
Let us consider this example of the operator of addition. An addition for a vector with N dimensions could be written as follows:
templateVector & Vector :: operator+= (const Vector & rhs) { for (int I = 0; I < dimension; i++) been worth += rhs.value; return *this; }
When the compiler instancie the function owner defined above, the following code is produced:
template<>
Vector<2>& Vector<2>:: operator+= (const Vector<2>& rhs)
{
been worth += rhs.value;
been worth += rhs.value;
return *this;
}
The optimizer of the compiler is able to unroll the loop for because the parameter dimension of the owner is a constant known with compilation. For a true implementation of this technique, to see.
In C++, the metaprogrammation with owners is Turing-complete, which means that any calculation exprimable by a program can be calculated by a métaprogramme containing owners.
The métaprogrammes containing owners do not have variable mutable, i.e. no variable can once change value it was initialized. That has as a consequence that contrary to C++ with the execution, the metaprogrammation containing owners is a form of functional Programmation. For this reason, the Analyze of flood in the métaprogrammes is made by the means of recursion, as considering higher
Initialization of data
In C++, the metaprogrammation with owners makes it possible to initialize a data like a table or a complex structure of data. The following example illustrates the filling of a table whose 32 values are the square of the index, and the following values are the index.
The template is used to make calculate the value of an element of the table:
template
To facilitate the filling of a large table, one can use traditional macros:
#define REMPLIR_TAB1 (I) ValeurTab< (I) >:: value
#DEFINE REMPLIR_TAB2 (I) REMPLIR_TAB1 ((I)), REMPLIR_TAB1 (I + 1)
#DEFINE REMPLIR_TAB4 (I) REMPLIR_TAB2 (I), REMPLIR_TAB2 (I + 2)
#DEFINE REMPLIR_TAB8 (I) REMPLIR_TAB4 (I), REMPLIR_TAB4 (I + 4)
#DEFINE REMPLIR_TAB16 (I) REMPLIR_TAB8 (I), REMPLIR_TAB8 (I + 8)
#DEFINE REMPLIR_TAB32 (I) REMPLIR_TAB16 (I), REMPLIR_TAB16 (I + 16)
#DEFINE REMPLIR_TAB64 (I) REMPLIR_TAB32 (I), REMPLIR_TAB32 (I + 32)
#DEFINE REMPLIR_TAB128 (I) REMPLIR_TAB64 (I), REMPLIR_TAB64 (I + 64)
//..
Thus to fill a table with 100 elements by respecting the algorithm of the owner of class, it is enough to write:
int = {REMPLIR_TAB64 (0), REMPLIR_TAB32 (64), REMPLIR_TAB4 (64 + 32)};
It may be that, in a program, an object of class UneClasseC is handled, at the time of various calls of functions (or methods), like an object of class UneClasseA in order to benefit from the advantages of polymorphism. However, it may be that have it has a specific treatment according to the real class of the object. For example, This frequently arrives for the graphic posting of an object when the program is cut out according to the concept MVC. This technique is a reason for design called visitor.
Classically, in C++, that is made by a downward coercion ( Downcasting in English). It is then enough to make the tests:
UneClasseB* pConvB = 0;
UneClasseC* pConvC = 0;
yew (pConvB = dynamic_cast
Here, the metaprogrammation makes it possible to make the program impossible to compile if one adds a type which is not treated nowhere.
For that, it is necessary to draw up a list of the types which will make it possible to check if all the treatments of each type were programmed.
template
It is then enough to create an abstract class which will be specialized with this list of the types. This class will be made nonabstract while implementing a pure virtual method for each type (methods by specific treatment). Thus, the lapse of memory of the implementation of the method of a type of the list, will generate an abstract class. An abstract class not being able to be instanciée, the compiler will turn over in error during the creation of the Visiteur object. It will then be enough to add the implementation of the method of treatment to the new type, to remove the abstract behavior of the class and to allow an instanciation. Thus, the compiler can then compile the program and no method of implementation will be forgotten.
It is thus necessary to create an abstract class visitor with an unspecified list of types:
template
Lastly, it is necessary to create the class which will implement all the specific treatments:
class Visitor: AbsVisiteur Compromised between compilation and the execution : as all the code in the form of owner is treated, evaluated and generated with compilation, compilation will take more time while the achievable code could be more effective. Although this addition is generally tiny, for large projects, or projects which use owners in great quantity, that can be important.
Control on compilation
Initially, some classes:
class UneClasseA
{
public:
UneClasseA () {}
virtual ~UneClasseA () {}
};
class UneClasseB: UneClasseA public
{
public:
UneClasseB () {}
virtual ~UneClasseB () {}
};
class UneClasseC: UneClasseA public
{
public:
UneClasseC () {}
virtual ~UneClasseC () {}
};
class UneNouvelleClasseD: UneClasseA public
{
public:
UneNouvelleClasseD () {}
virtual ~UneNouvelleClasseD () {}
};
Advantages and disadvantages of the metaprogrammation containing owners
Random links: Presumption of innocence | Couzou | Armonie Sanders | Route main road 85a | He' S Bonkers | 8_Flora