Chapter 3

xiaoxiao2021-03-06  77

David Abraham & aleksey Gurtovoy

Liu Weipeng (PP_Liu@msn.com)

With the previous basic knowledge, let's examine a most basic application of template programming technology - add a static type check to the traditional operation of the type check. To this end, we will investigate an example of engineering science - almost all the applications involving scientific calculations can be found. In the process of examining this example, you will learn some important new Concepts, and try to use MPL [1] (Metaprogramming Library) to perform high-order template programming.

3.1 Unit [2] analysis

The primary principle of physical calculations is that the value is not independent - most physical quantities have units. And we accidentally put the brain of the unit, this is a very dangerous thing. As the calculation becomes more complex, the correct unit of maintaining physical quantities can avoid errors that will be committed in unwillingness such as "assigning quality to the length" and "add acceleration and speed". This means establishing a type system for values.

The manual inspection type is a monotonous work and is easy to cause errors. When people feel bored, attention will be dispersed, which is easy to make mistakes. However, the type check is not the work of the computer? If we can build a C type Framework for physical quantities and units, then we can capture errors from the formula without waiting for problems in the real world.

The physical quantity interoperability of blocking units is not difficult - we can simply use classes to express units and only allow the same class (unit) interoperability. However, the problem is not to be as simple, and the different units can be combined by multiplying or incorporating, resulting in a complex new unit, because the new units produced are almost arbitrary because of the constant multiplication. It seems that the problem is more interesting! For example, Newton's law (it will linked strength, quality, acceleration):

F = ma

Since the quality and acceleration have different units, the force of the force must be the combination of both. In fact, the unit of acceleration is already a "mixture" - the change in speed in unit time:

DV / DT

Also because the speed is "the distance passing within the unit", the basic unit of acceleration is:

(L / T) / T = L / T2

Also, the acceleration is usually measured in "rice per square second". Therefore, the unit of force is:

ML / T2

That is, the force is usually measured in kg (m / s2) or "kilograms per square second". When we multiply the quality and acceleration, we must multiply the unit except the quantity, this can help us believe it is meaningful. The official name of this (for unit) bookkeeping is analyzed, while our next task is to implement it in the C type system. John Barton and Lee Nackman show how to implement it for the first time in their works "Scientific and Engineering C ". We will follow their ideas, but re-realize it.

3.1.1

Represent a unit

The standard unit system specifies the standard unit of physical quantity: mass (kg), length or position (m), time (s), charge (C), temperature (OC), density (kg / m3), angle (O) . For universal, our system must represent seven or more basic units, and it is also possible to represent composite units, such as power (kg (m / s2)) units through several basic units. Compound units. In general, a composite unit can see the product of a number of basic units [3]. If you want to indicate these powers, you can manipulate them in the running period, we can use an array, and the seven elements each correspond to a different unit, and its value represents the power of the corresponding unit:

Typedef int Dimension [7]; // m L t ...

Dimension const mass = {1,0,0,0,0,0};

Dimension constrangth = {0, 1, 0, 0, 0, 0, 0};

Dimension const time = {0,0,1,0,0,0,0};

...

According to this representation, the representation is as follows:

Dimension const force = {1,1, -2,0,0,0};

That is, MLT-2 is said. However, if we want to incorporate units into type system [4], these arrays cannot be eligible: their types are all the same, they are Dimension! What we need is that itself can represent the type of numerical sequence, such quality and length types are different, and the types of two quality are the same.

Fortunately, MPL provides a set of facilities that represent type sequences. For example, we can build a sequence of symbolic integer:

#include

Typedef Boost :: MPL :: Vector <

Signed Char, Short, Int, Long> Signed_Types;

So how do we use the type sequence to represent the unit [5]? Since the type of meta-function pass and the returned type is an outer cover with embedded: Value, the numerical sequence is actually a sequence of an overclock type (another polymorphic example). In order to make things simpler, the MPL provides an int_ type template, which represents its integer parameter N:

#include

Namespace MPL = Boost :: MPL; [6] // Namespace Alias

Static int const file = mpl :: int_ <5> :: Value;

In fact, the MPL library contains an overall overcharge, such as long_ and bool_, etc., each overlay corresponding to a different type of integration.

Now we can build basic units as follows:

Typedef MPL :: Vector <

MPL :: INT_ <1>, MPL :: INT_ <0>, MPL :: INT_ <0>, MPL :: INT_ <0>

, MPL :: INT_ <0>, MPL :: INT_ <0>, MPL :: INT_ <0>

> mass;

Typedef MPL :: Vector <

MPL :: INT_ <0>, MPL :: INT_ <1>, MPL :: INT_ <0>, MPL :: INT_ <0>

, MPL :: INT_ <0>, MPL :: INT_ <0>, MPL :: INT_ <0>

> Length;

...

Oh ... You will soon think this is too tiring. Worse, this code is difficult to read and verify. The essential information of the code, that is, the power of each basic unit, is buried in a repeated syntax "noise". Therefore, the MPL also provides an integer sequence outcrow, which allows us to write like the following code:

#include

Typedef MPL :: Vector_C Mass;

Typedef MPL :: Vector_C Length; // OR Position

Typedef MPL :: Vector_C TIME;

Typedef MPL :: Vector_C Charge;

Typedef MPL :: Vector_C Temperature

Typedef MPL :: Vector_C intensity;

Typedef MPL :: Vector_C Angle;

You can view this special MPL :: Vector_c as like the length of the length of the MPL :: Vector, although their types are different.

If we are willing, we can also define some composite units:

// Basic unit: M L t ...

Typedef MPL :: Vector_c Velocity; // L / T

TypedEf MPL :: Vector_c Acceleration;

// l / (t2)

Typedef MPL :: Vector_C Momentum; // ml / t

Typedef MPL :: Vector_C Force; // ml / (t2)

And, sometimes the unit of the scale (such as Pi, the unit of the scalar is not unit-translation) can also be described:

Typedef MPL :: Vector_C scalar;

3.1.2

Physical quantity

The type listed above is still pure metadata. To perform type checking for true computing, we also need to bind them (metadata) to runtime data in some way. A simple numerical outcrow - template parameter is the unit of data type T and T. Just right:

Template

Struct Quantity

{

Explicit Quantity (T X)

: M_Value (x)

{}

T value () const {return m_value;

Private:

T M_Value;

}

Now, we have a way to link values ​​and units. For example, we can say:

Quantity L

1.0f

);

Quantity m

2.0F

);

Note that there is no figure of the Dimensions template parameter in the Quantity class definition body, which only appears in the template parameter list, which is to ensure that L and M have different types. In this way, we can't define the length to quality:

m = L; // Compile period error

3.1.3

Implement addition and subtraction

Because the type of parameters must always match, we can now easily write the rules of addition and subtraction:

Template

Quantity

Operator (Quantity X, Quantity Y)

{

Return Quantity (x.Value () y.Value ());

}

Template

Quantity

Operator- (Quantity x, quantity y)

{

Return Quantity (X.Value () - Y.Value ());

}

In this way, we can write out the following code:

Quantity len1 (

1.0f

);

Quantity len2 (

2.0F

);

Len1 = len1 len2; // ok

And, we can't add the amount of different units:

Len1 = len1 = quantity

3.7F

// error

3.1.4

Multiplication

Multiplication is more complicated than plus reduction. So far, the parameters and results of the operation are the same, but when multiply, the unit is often different from the units of the two parameters. For multiplication, the following form:

(XA) (XB) = X (A B)

The index of the unit of the result is the index of the unit of the corresponding parameters. The business is similar to the index.

To do this, we use the MPL Transform algorithm to add the corresponding elements in the two sequences. Transform is a dollar function that traverses two parallel input sequences, transmitting the corresponding elements in the two sequences to an arbitrary (providing) binary function for each location, and store the result into an output sequence.

Template

Class sequence2,

Class binaryOperation

>

Struct Transform; // Return A Sequence

If you are familiar with STL's Transform Algorithm, the above Struct Transform has the form of you may not be unfamiliar, the STL's Transform algorithm accepts two running input sequences:

Template <

Class InputITOR1, Class InputItitor2

, Class OutputItitor, Class BinaryOperation

>

Void Transform

InputItitor1 start1, inputiterator2 finish1

, InputItemrator2 start2

Outputiterator Result, binaryoperty func;

Now we only need to deliver a binaryOperation for the MPL :: Transform to perform a multi-division method (by adding a corresponding element of the two sequences). If you look at the MPL reference manual, you will see that both Plus and Minus are just right: #include

#include

#include

Namespace MPL = Boost :: MPL;

Boost_static_assert (((

MPL :: Plus <

MPL :: INT_ <2>

, MPL :: INT_ <3>

> :: Type :: Value == 5

));

BOOST_STATIC_ASSERT is a macro if its parameter is false, will cause a compile period error. Braces are necessary because the C preprocessor cannot resolve the template: If there is not added a pair of parenthesis, then it will use a comma of the template parameters as a comma that is separated by a macro parameter, thereby incorrectly resolving the conditional expression into a number Macro parameter. This is not the same as the running period (...) (...) is different (the latter is parsed by C , you can identify all expressions - translation), boost_static_assert can also be used in the defined domain of the class, allowing us to allow us to Placed in a metaper. Chapter 8 has a more in-depth discussion.

So far, we seem to have a solution, like this:

#include

Template

QUANTITY <

T

, Typename MPL :: Transform :: Type

>

Operator * (Quantity x, quantity y) {...}

But I am sorry, this is not enough! Now if you try to use this Operator *, you will get a compilation error because you will pass MPL :: Plus to MPL :: Transform, and (MPL) stipulates that the parameters of the key function must be type, but MPL :: Plus is not type, but a class template. So we have to make a metadata model in some way to meet the metadata models like PLUS.

In a sense, this requires introduction of the polymorphism between metadata and metadata, a natural way is to use an outcrotturity method - in the previous code, this idiom method has been type and A polymorphism is introduced between integration constants. Now, we embed a class template in a so-called meta-function class [7]:

Struct Plus_f

{

Template

Struct Apply

{

Typedef TypeName MPL :: Plus :: Type Type;

}

}

Definition: The meta-function class is a class that is embedded as a PUBLIC meticulum function named Apply.

Although the meticone is a template rather than type, the meta-function class is covered with a normal non-template class to make it a type. Because the metadata operations and returns are type, the meta-function class can also be passed to another meta as parameters, and the meticulous function can also return a meta-function class.

Thus, we get a PLUS_F element function class, transfer it as a binaryOperation to MPL :: Transform does not cause compilation error: Template

QUANTITY <

T

, Typename MPL :: Transform :: Type // New Dimensions

>

Operator * (Quantity x, quantity y)

{

TypeDef Typename MPL :: Transform :: Type Dim;

Return Quantity (x.Value () * y.value ());

}

Now, if we calculate one

5

kg

The gravity of the laptop, that is, the gravity acceleration is multiplied by quality:

Quantity m

5.0f

);

Quantity a

9.8F

);

Std :: cout << "force =" << (m * a) .value ();

Our custom Operator * multiplies these rules (the result is

49F

And our metrorate code will add the element sequence of the basic unit of the specified unit by Transform, so the result type is a new unit, which means that it is like this:

MPL :: Vector_c // kgms-2

However, if we try to write:

Quantity f = m * a;

We will encounter a little problem. Although the results of M * a have indeed: mass, length, time index is 1, 1, -2, but the type returned by Transform is not vector_c. Instead, Transform handles its input elements and creates a new sequence with the appropriate elements: this new sequence and MPL :: Vector_C have almost the same Attributes, but they are totally different C types. If you want to know the full name of the new sequence, you can try to compile this example, then view the error message, but the exact details are not important. The key issue is that the type of Force is different and the type of new sequence is different, so assignment will fail.

To solve this problem, we can add an implicit conversion from the multiplication result type to Quantity . Since we cannot predict the exact type of intervention calculated units (so that the unit-translation of the calculated results cannot be predicted), this conversion must be in the form of template, like this:

Template

Struct Quantity

{

// Converting Constructionor

Template

Quantity (Quantity Const & RHS)

: M_Value (rhs.value ())

{

}

...

However, unfortunately, such a general conversion completely violates our original intentions, once this conversion, we can write the following code:

// m * a The result should be force, not quality (mass)! QUANTITY bogus = m * a;

This is getting awful!

Fortunately, we can solve this problem through another MPL algorithm --equal - Equal is used to test whether two sequences have the same episode:

Template

Quantity (Quantity Const & RHS)

: M_Value (rhs.value ())

{

Boost_static_assert (((

MPL :: Equal :: Type :: Value

));

}

Now, if the two units do not match, this assertion will cause a compilation error to prevent your error behavior in time.

3.1.5

Realize division

The division and multiplication are similar, and the multiplication adds the index, and the division is reduced. Obviously, the meta-function class minus_f can be written in the form of PLUS_F, but here we will use a new skill to make the minus_f element function class simpler:

Struct minus_f

{

Template

Struct Apply

: MPL :: Minus {};

}

Here, Minus_f :: Apply uses inheritance to expose its base class MPL :: Minus "Type" embedded type. This way we don't have to write:

TypedEf TypeName ... :: Type Type

This powerful simplified code is called a meticulous force forward. Behind we will use it frequently. Note that we don't have to use TypenAme in front of the base class MPL :: Minus , because the compiler knows that there is only type in the list of Apply's base class.

Despite such grammar skills to simplify the code, it will still be bored with these simple outsmen over and off. Although minus_f is so bloated, you still have to write a bunch of code for this. Fortunately, MPL provides us with a much more simple way, we don't need to write a whole elementary function class (such as minus_f), but can "directly" to pass the meta-function to the algorithm, for example, we can call MPL :: Transform:

Typename MPL :: Transform > :: Type

Two of them look very strange parameters (_1 and _2), they are called placeholders, where they mean: When Transform's BinaryOperation is called, the first second parameter will be correspondingly Pass to MINUS _1 and _2. MPL :: Minus <_1, _2> is called placeholder expression.

Note: The MPL placeholder is located in the MPL :: PlaceHolders namespace, defined in the boost / mpl / placeholder.hpp file. In this book, we will assume that you have already written the following code:

#include

Using Namespace MPL :: Placeholders;

In this way, the placeholders like _1, _2 can not add access to name space.

Operator / like this using placeholders:

Template Quantity <

T

, Typename MPL :: Transform > :: Type

>

Operator / (Quantity x, quantity y)

{

Typedef Typename

MPL :: Transform > :: Type Dim;

Return Quantity (x.Value () / y.value ());

}

The code is significantly more concise (because one minus_f class is not used). We can also decompose the code of the new unit to a new meticulum, which will continue to be simplified:

Template

Struct Divide_dimensions

: MPL :: Transform > // Re-forwarding again

{};

Template

Quantity :: type>

Operator / (Quantity x, quantity y)

{

Return Quantity :: type>

X.Value () / y.value ());

}

Now we can verify that the gravity of the laptop calculates correct, through a reverse calculation, we get its quality, then compare the computers given by the condition:

Quantity m2 = f / a;

FLOAT ROUNDING_ERROR = std :: abs ((m2-m) .value ());

If everything is normal, then rugging_error will be very close to 0. Although these calculations are bored, if they go wrong, they often destroy the entire program (even worse). If we write F / A to A / F, we will get a compilation error, prevent errors from spread throughout the program.

3.2 Higher-Order MetaFunctions

In the previous section, we use two formats-meta-function classes and placeholder expressions when we pass or return meta. By putting the metadata "In the metadata of the" First Class, the Transform can be allowed to perform a variety of different operations, for example, the unit multiplied in the above example. Although the idea of ​​"using functions to manipulate other functions" is relatively simple, but there is very powerful ability and flexibility, so I have won a nice name: Higher-Order Functional Programming. The function of manipulating other functions is called a high order function. Therefore, Transform is a high-order metader function: a meta function for manipulating other metades.

Now we have seen the powerful power of high-order metadata. Here we will try to create new high-order metadata. In order to explore its underlying mechanism, let's first look at a simple example. Our task is to write a meta-called TWICE, TWICE satisfies the following conditions: give it a yuan function f and any metadata X, which will make the following calculation:

TWICE (f, x): = f (f (x)) This example doesn't seem to value - it does not. You probably not use TWICE in actual coding. But using it is not our purpose, TWICE contains all the necessary elements of "high-order metader function" and does not make your attention to other details, although it just accepts and calls a meta function.

If F is a class function class, then TWICE definition will be intuitive:

Template

Struct TWICE

{

TypeDef TypeName F :: Template Apply :: type overce; // f (x)

TypeDef TypeName F :: Template Apply :: Type Type; // F (f (x))

}

Or use a meta-function forwarding:

Template

Struct TWICE

: F: Template Apply <

TypeName F :: Template Apply :: TYPE

>

{};

C language. Note

C standard requirements: When we use the Dependent Name and the name refers to a member template, we must use the template keyword. F :: Apply does not necessarily mean a template name, its meaning depends on F. And F :: Template Apply is exactly the compiler Apply (should) is a member template. About Template, Appendix B has more information.

Obviously, when each function class is used, it is a burden before apply, and the burden can be reduced by breaking this mode pattern into a meta function:

Template

Struct Apply1

: UnarymetaFunctionClass :: Template Apply

{};

Now, TWICE can be simplified to be like this:

Template

Struct TWICE

: Apply1 :: type>

{};

Let's take a look at the TWICE - Apply it to the add_pointr_f meta function class:

Struct add_point_f

{

Template

Struct Apply: boost :: add_pointer {};

}

Boost_static_assert (((

Boost :: is_same <

TWICE :: Type

Int **

> :: Value

));

We can see that TWICE and ADD_POINTER_F use can create a "pointer".

3.3 Treatment of placeholders

Although our TWICE implementation has been working with the metamorphic class, we also require it to work with the placeholder expression, just like Transform allows us to deliver two forms of meta. For example, we have to write this code:

Template

Struct Two_Pointers

: TWICE , x>

{};

But we will find that the implementation of Boost :: Add_Pointer will find that the current TWICE does not work at all: Template

Struct add_pointer

{

TYPEDEF T * TYPE;

}

Boost :: add_pointer <_1> must be a dollar function class (just like add_pointer_f) to be called by TWICE. However, in fact it is a nullary meticulum function, returning almost meaningless _1 * type. All things that try to use Two_Pointers will fail because when Apply1 requires the boost :: add_point <_1> embedded :: Apply meticulum, it will find that it does not exist at all.

We did not get the behavior they wanted. What should I do now? Think about it, since MPL :: Transform can do it, then we should have a way - below:

3.3.1

Lambda meta function

We can use the MPL's lambda meta function, generated by boost :: add_pointer <_1>:

Template

Struct Two_Pointers

: TWICE > :: type, x>

{};

Boost_static_assert (((

Boost :: is_same <

TypeName Two_Pointers :: Type

Int **

> :: Value

));

Later, we will collect the placeholder expressions such as add_pointer_f or Boost :: add_point <_1> such a placeholder expression that represents the lambda expression. The meaning of this name is "Unnamed" function object, which is introduced by logistist Alonzo Church in the 1930s, as a calculated theory called Lambda-Calculus [8]) a part of. The reason why this meaning using lambda is a bit obscured because it is established in the functional programming language.

Although MPL :: Lambda's main intention is to convert placeholder expressions into a meta-function class, it can also accept any Lambda expression, even if the expression is already a dollar function class. In the latter case, MPL :: lambda returns its parameters. The MPL algorithm (such as Transform) uses MPL :: Lambda internally, and then calls it to return (generated) the meta-function class, so they are all right than two lambda expressions. We can apply the same policy to TWICE:

Template

Struct TWICE

: Apply1 <

Typename MPL :: Lambda :: Type

, Typename Apply1 <

Typename MPL :: Lambda :: Type

, X

> :: Type

>

{};

Now we can use TWICE and meticular or placeholder expressions:

INT * X;

TWICE :: type p = & x;

TWICE , int> :: type q = & x;

3.3.2 a

PPLY element function

The meta-function class that calls Lambda is extremely common in the MPL, so that the MPL provides an Apply meticulous function to do this. Using MPL :: Apply, our twice will become more flexible: #include

Template

Struct TWICE

: MPL :: Apply :: type>

{};

You can regard MPL :: Apply as the same as Apply1, but Apply has two features:

1. Apply1 can only operate the metadata class, while the first parameter of MPL :: Apply may be any LAMBDA expression (including placeholder expressions) [9].

2. Apply1 can only accept 1 additional parameters other than the meta-function class, and pass this parameter to the meta-function class. MPL :: Apply accepts 1 to 5 additional parameters [10], and uses them to call the metabic class. E.g:

// Apply binary Lambda expression to another two parameters

MPL :: Apply <

MPL :: Plus <_1, _2>

, MPL :: INT_ <6>

, MPL :: INT_ <7>

> :: type :: value // == 13

in principle

If you want to call it a parameter in your meta (ie: call a parameter as a meta-translation class), use MPL :: Apply to ensure that the call is both lambda expressions. Effective.

3.4 Other Abilities of Lambda

The ability of the Lambda expression is not stopped by making the meticulous parameters. The other two capabilities described below make the lambda expression into an indispensable part of almost every primary programming task.

3.4.1

Partial Metafunction Application

Consider Lambda Expressions MPL :: Plus <_1, _1>: Single parameters are passed to the two "_1" positions of PLUS, that is, add a value to itself. Therefore, here, a binary element is used to create a one-dollar lambda expression. In other words, we have created a new operation (Plus originally doing the additional operation, but plus <_1, _1> is added to itself, but also "

2

"

Operation - translation)! However, more than this, by binding a normal type (non-placeholder) to one of the parameters of the PLUS, we can create a one-yuan Lambda expression that acts in adding its parameters (such as 42 ):

MPL :: Plus <_1, MPL :: INT_ <42>>>>

Process of a subset of a set of consolidations to a function of a function to a function is referred to as partial function applications in Functional Programming Language [11].

3.4.2

Composite meta function [12] (MetaFunction Composition)

The Lambda expression can also be used to combine simple meticulum to produce more interesting operations. For example, the following expression will multiply the two numbers (ie (A B) * (A-B) - translation):

MPL :: Multiplies , MPL :: Minus <_1, _2>>

It can be seen that it is a complex of three meta functions (Multiplies, Plus, Minus).

When you evaluate a LAMBDA expression, MPL will check its parameters to determine if they are lambda expressions [13], if yes, first pay them, and put them (itself is lambda expression) The parameter replaces the result of the value, and then evaluates the peripheral LAMBDA expression [14]. 3.5 Details of Lambda

Now you should have a roughly understanding of the semantics of MPL's Lambda facilities. In this case, let us formulate the previous understanding (formal), and examine some more deeper things.

3.5.1

Placeholder

The definition of "placeholder" may scare you:

definition

The placeholder is a meta-like MPL :: arg .

3.5.1

.1 Implementation

_1, _2, _3 These names are only for convenience, in fact, they are MPL :: arg's special version of TypeDefs, MPL :: arg as a function of meticulous function is selected (and returned) its N parameters [15]. The realization of placeholders is like this:

Namespace boost {

Namespace MPL {

Namespace Placeholders {

Template struct arg; // preamble declaration

Struct void_;

Template <>

Struct Arg <1>

{

Template <

Class A1, Class A2 = VOID_, ... CLASS AM = VOID_>

Struct Apply

{

Typedef A1 TYPE; / / Returns its first parameter

}

}

TYPEDEF ARG <1> _1;

Template <>

Struct Arg <2>

{

Template <

Class A1, Class A2, Class A3 = VOID_, ... CLASS AM = VOID_

>

Struct Apply

{

TypeDef A2 Type; // Returns its second parameters

}

}

TYPEDEF ARG <2> _2;

// Other specialty version and typedefs ...

}}}

As mentioned earlier, the calling meta function class is to call its embedded :: Apply meticulous function. When a placeholder in a lambda expression is evaluated, it is actually called the placeholder with the actual parameters of the lambda expression, and then the placeholder will return to some of the parameters [16]. The result is then evaluated (returned) will replace the location of the placeholder in the LAMBDA expression. So repeated until all placeholders are replaced with the (actual) parameters they represent.

3.5.1

.2 anonymous (unnamed) placeholder

Anonymous placeholders are a very special placeholder, which is defined as follows:

Namespace Boost {Namespace MPL {Namespace PlaceHolders {

Typedef arg <-1> _; // anonymous placeholder

}}}

It is not important for details. For anonymous placeholders, what you need is: it is treated special. When a lambda expression is converted to a meta function class by MPL :: lambda, the anonymous placeholder in a given template specialty is replaced with_n.

For example, each line in Table 3.1 below contains two equivalent LAMBDA expressions:

chart 3.1

MPL :: Plus <_, _>

MPL :: Plus <_1, _2> Boost :: IS_SAME <

_

Boost :: add_point <_>

>

Boost :: is_same <

_1

, Boost :: Add_Pointer <_1>

>

MPL :: Multiplies <

MPL :: Plus <_, _>

, MPL :: Minus <_, _>

>

MPL :: Multiplies <

MPL :: Plus <_1, _2>

, MPL :: Minus <_1, _2>

>

3.5.2

Definition of placeholder expression

Now you should already know the meaning of the placeholder. In this case, we can define placeholder expressions as follows:

definition

A placeholder expression is:

A placeholder

or

One of its parameters has at least one template special chemistry for placeholder expression.

In other words, a placeholder expression always contains (at least) one placeholder.

3.5.3

Lambda and non-metafunction template

With regard to placeholder expressions, a detail that has not been discussed is: In order to make ordinary templates more easily integrated into meta-programming, MPL uses special rules for them. After all of the placeholders are replaced with the corresponding actual parameters, if the template special chemical X as a result is not embedded :: Type, then the result is X itself.

For example, the results of MPL :: Apply , t> are always std :: vector . If it is not because of this behavior, we have to write a meta-function to create a template specialty in the Lambda expression:

// Trivial Std :: Vector Generator

Template

Struct Make_vector {typedef std :: vector type;};

Typedef MPL :: Apply , t> :: type vector_of_t;

But now because of this special rule, we can write:

Typedef MPL :: Apply , t> :: type vector_of_t;

3.5.4

"Lazy" importance

Review the always_int mentioned in the previous chapter:

Struct Always_Int

{

Typedef int Type;

}

Nullary meticulous function may appear to look, as the type of type ADD_POINTER can be replaced with INT * in any place in any lambda expression. But not all non-refined function is like this simple! E.g:

Struct add_point_f

{

Template

Struct Apply: boost :: add_pointer {};

}

Typedef MPL :: Vector seq;

Typedef MPL :: Transform CALC_PTR_SEQ;

Note that Calc_ptr_seq is a non-refined function, because it has the embedded embedded :: Type. However, for a C template, it will only be instantiated when we try to "observe their interior". Just use CALC_PTR_SEQ as a TypeDef name and does not cause it to be evaluated, because we have not access it inside: Type.

The meticone can still be delayed after accepting its parameters. When a meta-function is only selective, we can use inert evaluation [17] (lazy emaluation) to reduce compilation time. Sometimes, by naming [18] is not actually executed, we can also avoid distortion program [19]. We do this for Calc_ptr_seq, because Double & * is an illegal type. This "lazy" and its advantage are the topics that will be repeated in this book. 3.6 details

So far, your basic concepts and languages ​​of a general template programming and Boost's MPL library should have a considerable understanding. This section reviews the main points.

Metafunction Forwarding

Use public inheritance to expose :: TYPE to the user's technology [20].

MetaFunction Class

The most basic method of forming the compilation function, thereby, the compilation function can be seen as a polymorphic metadata, which is to see as a type. The meta-function class is a class that is embedded as a meta-name.

MPL

Most of this book uses Boost Metaprogramming Library (ie MPL). Like the header file of Boost's Type Traits, the MPL header file follows a simple agreement:

#include

However, if a component of the MPL is finished, the corresponding MPL header file name does not include the final underscore. For example, MPL :: BOOL_ can be found in . If the library does not follow this agreement, we will point out you.

Higher-Order Function

Operation or return function of the function. Using other metadata makes a meta-state programming a key to high-order metadata.

Lambda expression

Simply put, the lambda expression is metadata that can be called. If there are no modified metadata, the high-order metader is not possible. Lambda expressions have two basic forms: meta-function class and placeholder expressions.

Placeholder expression

One of the lambda expression. The purpose of the partial function application and the composite meta function is achieved by using the placeholder. As you will be seen everywhere in this book, these features give us amazing ability, allowing us to construct almost any complicated type calculations from the original meta-function - it is used:

// Find the position of a type x in some_sequence such That:

// x is converTible to 'int

// && x IS not 'char'

// && x IS not a floating type

TypedEf MPL :: Find_if <

Some_sequence

, MPL :: And_ <

Boost :: IS_CONVERTIBLE <_1, INT>

, MPL :: Not_ >

, MPL :: Not_ >

>

> :: Type ITer;

The placeholder expression makes us do not have to write a new (overcharge) meticulum class, and achieve the purpose of algorithm multiplexing. This ability is seriously lacking in the world of STL's period of time, because if the correctness and efficiency of the standard algorithm, a loop is often much more simpler than the standard algorithm.

The 'Lambda' MetaFunction converts the Lambda expression into a meta-functional function. To get more detailed information about the Lambda and Lambda evaluation process, please refer to the MPL reference manual.

Apply meta function (the 'Apply' MetaFunction)

A meta function, its behavior is: call its first parameter with the remaining parameters, the latter must be a lambda expression. Typically, to call a lambda expression, you should always pass it and call it to MPL :: Apply instead of "manual" using MPL :: lambda.

Lazy Evaluation

A strategy that will calculate when it is postponed to its result. This strategy avoids all unnecessary calculations and unnecessary errors. The meticone is only called (true) when we have access to its embedded :: Type, so we can not make any substantive calculations while providing all the parameters, but will delay the requirements to the necessary time.

The translator presses. Postscript:

Call, three nights, finally ended this chapter, I feel that the translation is not bad, because it is the master's work, so the translation is excellence, it can be said to be "war" :)

This book has also opened an appendix, talking about the mechanism of Boost Preprocesser Library. It is also clear that it is clear. Try to grasp the translation.

In the Boost library, the most difficult research is MPL and Preprocesser Lib. Now the master describes its design concept for our high-hofed, so that we will not be blinded by heavy detail.

I used to spend Kung Fu studied the MPL and Preprocesser section inside the Boost library, but because there is no guidance of the abstraction, it is very difficult, the result is still a semi-solving, but this time I use the translation opportunity to see the part that doesn't understand. Once, I really have the feeling of "dialing the clouds."

I used to read Houjie and Yuchun

view

When Mr. Modern C Design, read

Hou Jie

Mr.'s translation, Mr. said "瞠 瞠 结" in the translation, and I will see the MPL of the Boost library after reading "Modern C Design" translated, still only four words "瞠瞠 结". I always feel that I have learned C and I don't learn a generic. It is more than half of the school, but I don't look at "Modern C Design" is less than half, and now I think, generic flop And don't learn Template metaprogramming, is equal to less than half, and learn Template Metaprogramming does not look at this upcoming potential to become a "Bible" C Template Metaprogramming book, simply did not learn C template metaprogramming. !

I am looking forward to this "classic classic" in this "classic classic".

About translation

I know that many people discuss issues about technological translation, so I don't have to draw snakes, just asked, write a little bit perhaps.

As C 's father Bjarne Stroustrup said: "Many times the solution is not not, but too many, so we have to weigh the advantages and disadvantages," Of course, the original text is not the case, but the same). The same is true for translation, and "Too many translations is too many" is the richness of Chinese semantics, but this richness also brought the attachment - sometimes a sentence that does not have a disambiguated ambiguity in English if It may be unsatisfactory and even polymity, or the simplicity is unpredictable, so sometimes it is necessary to avoid the semantic ambitions, only the semantic sentence, re-combined. At this time, the translator is required to completely lead the author's meaning and have certain Chinese expressions. The other is about logic. Due to the flexibility and strinity of the attribute in English, English is often able to write a few reason for a few reasons, which may also cover other auxiliary information, but Chinese is different, you will find problems after a number of "" " This time you have to remove it.

Therefore, individuals feel that translations are alive, and the Chinese level is most important. It is easy to say that "Shun" is really easy.

[1] MPL is a sub-library in the Boost library. Used to support template meta programming. This MPL library will be mentioned more below.

[2] Translation: Here is Dimensional Analysis, which is not a "dimension" explanation in the usual sense. Instead, as a physical "unit" explanation, however, how to explain the physical quantity in the compile period, in turn to achieve a sound unit system for a compile period. The formal styling of Dimensional Analysis is "quantitative analysis", too academic, so we use usually physically styled.

[3] Watch 1 / x as X -1. Thus, M / S2 can be written into MS-2, which is in the form of a product.

[4] Translation: The author means "let each of the units become different types".

[5] Translation: The original article here is "... represent number", translated into "... Represents value", but what is meant here is a unit of value.

[6] Namespace alias = namespace-name; declare Alias ​​as an alias of Namespace-Name. In many examples of this book, MPL :: is used to represent boost :: mpl ::.

[7] Translation: The meticulotics itself is a class template. The meta-function class is a type, which embides the meta-function class template, which will be mentioned later, please pay attention to their differences.

[8] http://en.wikipedia.org/wiki/Lambda_calculus

[9] Translation: But it seems to boost

1.31.0

The MPL :: Apply inside does not have this feature. Maybe it is considered after weighing?

[10] The Configuration Macros section of the MPL Reference Manual describes how to change the number of parameters that MPL :: Apply acceptable.

[11] Translation: The original article of the author is "... in the world of functional programming ...", this translation is "... in the functional programming ...", however, "Functional programming "Mislee may occur, and translation is" in function programming languages ​​", because the latter is a widely used noun.

[12] Demand: Here you can also translate "meticulum" "meticulum synthesis", etc., depending on the translation of Composition. However, considering the "compound function" in mathematics, so it is translated into a "composite element function", "composite" can be verb, which can be adjective. If the inflict is the "composite the meticulum", this is the meaning of the original text. If the adjective indicates that "the meta-composite function", this is the result of "composite". This seems to be better :). [13] Translation: The various parameters of the lambda expression herein are not the "external" parameters accepted by the lambda. For example: Mul , minus <_1, _2>> this lambda expression The parameters are Plus <_1, _2> and minus <_1, _2> and they are each lambda expression, so they will be evaluated first, and then pass the results to MUL.

[14] Demo: In fact, the evaluation of the Lambda expression is a recursive process.

[15] MPL provides 5 placeholders. The Configuration Macros section of the MPL reference manual has a description of how to change the number of placeholders provided.

[16] Translation: If the placeholder is _n, then return the Nth parameters in the actual parameter, the meaning of "occupying" of the placeholder is: _n "accounting" is the nth parameter position.

[17] The translation: Lazy Evaluation means "not seeking value if necessary".

[18] The translation: here, "Naming" means that only one name is given (meaning "instantizes its name"), and does not evaluate the calculation (meaning "is not instantiated This class ").

[19] Demonstration: A nice example is Apply_if, which detail the official documentation of Boost.

[20] Translation: The original text here is quite embarrassing, so the translation follows the definition of the above. The meaning is the same.

Published on September 01, 2004 6:14 AM

comment

#

Reply: "C Template Metaprogramming" Chapter 3 Depth Discovery Element

2004-09-01 8:34 AM

Zhao Zhongxiang

Support the landlord. very good. Where is the original version of the English download.

#

Reply: "C Template Metaprogramming" Chapter 3 Depth Discovery Element

2004-09-01 9:44 AM

Firingme

Can you change the typography? The font is too small ... Can't see clearly ...

#

Reply: "C Template Metaprogramming" Chapter 3 Depth Discovery Element

2004-09-01 9:56 AM

Zeng Yi

This book will only be published in November 2004, and now there are only two open chairs.

BTW: Liu Xiong, you will give me the next article, I will go to CSTC.

#

Reply: "C Template Metaprogramming" Chapter 3 Depth Discovery Element

2004-09-01 5:01 PM

Liu Weipeng

Due to this blog version of the typography, the font size is not good, everyone can copy to Word, enlarge, and read again. Sorry.

TO Fireingme:

Your reply font is also very small, huh, huh

BTW. English version download address to see the Boostconsult website. I also hope, search it.

#

Reply: "C Template Metaprogramming" Chapter 3 Depth Discovery Element

2004-09-02 9:43 AM

Firingme

In order to publish this TMP, there are already people who have not been happy ... Dave insists that as this book releases a stable version of MPL, but now some Features have not finished yet, so this time Boost 1.32.0 The release of some difficult tastes have been delayed for nearly one month. Maybe wait another 2 to 3 worships. However, although the information in CVS said that Serialization will be officially released in this release, but the author of Serialization is still not stable and robust now, can only be an Add - ON thing. I remember that there was a Bjarne interview that he felt that the most regrettable in the standard library was support for concurrency and persistence. I don't know this SERIALIZATION library that can not get the general recognition of C communities. #

Reply: "C Template Metaprogramming" Chapter 3 Depth Discovery Element

2004-09-02 3:18 PM

Liu Weipeng

Hope, this soft rib in C does not know when it can completely solve it. However, BJARNE is working with the stuff similar to Reflection to C , huh, huh, another "if you don't have to come out", but if such language (library) will be more complicated.

#

Reply: "C Template Metaprogramming" Chapter 3 Depth Discovery Element

2004-09-03 6:16 PM

Firingme

Liu brother is best to remove this translation into 3, 4 pages. Such a big piece of head is really dizziness ~! Today, DAVE finally puts the new version of the MPL to Boost CVS Tree, and there must be Boost 1.32.0 immediately! look forward to!

#

Written in the history of C book publishing history before the classics

2004-09-03 7:49 PM

AB

Ping Back from: blog.9cbs.net

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

New Post(0)