Recurrent beauty - Loki library Typelist source code analysis

zhaozj2021-02-16  45

Recurrent beauty - Loki library Typelist source code analysis

Deng Hui

Typelist Overview

When you mention List, you will not be unfamiliar, it is a collection of elements, and provides some methods for operating the collection, such as: Calculating the number of elements in the collection, adding an element to the collection, get a given index Elements, etc. The elements in the list we are well known are generally valued values, and the relevant operations are also carried out during operation. This article will analyze the List and the above List relatively preferred in a sense, but it includes the type (TYPE), the related operation is done during compilation.

This article will tell the Typelist's power to "Modern C Design" book "Modern C Design", and C lovers will not be strange, in the book, the author shows us C New thinking, the expression capability of C has been used to the extreme, and the Loki library is the specific performance of this thinking. Typelsit is the most foundation, core component in the Loki library, and understanding Typelist has the basis for watching this C new landscape.

Let's take a look at how to define a Typelist, so you can have a sense of sensibility for Typelist.

TypeDef Typelist_3 (CHAR, INT, long) Mytypelist;

Typelsit with three elements is defined, these three elements are: char, int, long. Typelist_3 is a tool for defining type of Typelist in the LOKI library, we will introduce later in this article.

:: LOKI :: Length :: value;

Calculate the number of elements in MyTypelist, resulting in 3.

Typedef :: Loki :: Typeat :: result mytype;

Get the first element in MyTypelist (starting from 0), at this time myType is int.

Typedef :: loki :: append :: result mytypelist1;

Add an element to mytypelist: float, result is mytypelist1. At this time: Length :: Value is equal to 4.

Ok, let's introduce so much. Below we will introduce some related background knowledge implemented by Typelist, including: the basic concept of recursive, Tempalte Specilization, Template Offerness (Template Offer Specilization) and Type Extraction Type Traits.

Typelist related technology recursive overview

For recursive, everyone is certainly unfamiliar, and the solution to the recursive method is always very elegant and concise. However, the problem that the recursive method is suitable for solving should comply with the following conditions:

Solution to a problem reliance on a smaller size must have a clear end condition that this end condition is up to

If a problem meets the above three conditions, we can use the recursive method. First we define a set of rules that solve problems, then reduce the size of the problem and apply the same rule until the end condition, then the result layer returns until the original problem. The famous Hanno Tita issue is a typical recursive issue. If the recursive method is not used, the problem of Hanno Tower will seem very complicated and obscure. When we use the recursive method design program, the call to this recursive process is always done during operation. In the implementation of the Typelist described herein, the recursive execution is done during the compilation period, then how to define each recursive return result during the compilation period, how to define the end condition? Among them, the templates, offset, and type extraction techniques will be described below will be used. Template Template Template Specilizaiton, Partial Specilization

What is the test of the template, is off? The general meaning is: If a template has one or more template parameters, we can conduct a specialization for one or more parameters (if all specialization processing is the full-term, otherwise it is offset, remember: Function templates can only be fully characterized, and partial specialization cannot be performed). That is, we can provide a special version that meets generalization conditions, but some (all) the template parameter has been replaced by the actual type or numerical value.

Suppose we have a Class Template definition as follows:

Template

Class C {...};

For the bias of the template, there may be some misunderstandings that may exist: it is to specify a certain parameter value for the Template's offset version of the template specify a parameter value. In fact, it is not the case, the so-called template is referred to as a definition of Template, and its specific meaning can be independent of the universal Template definition version. In a bias version, the number of Template parameters does not need to match the number in the universal Template. However, the number of parameters after the Class name will appear to match the number of parameters of the universal Template. Let's take a simple example to explain:

Template

Class C {...};

This generic version allows T to be any type. Its offset version is as follows:

Template

Class C {...};

This offset version is only available for T as the native pointer type.

When we use C to define a variable, the compiler will automatically use generic versions. If you define a variable with c , the compiler will automatically use the offset version. With this tool, we can solve the problem of ending conditions that are defined during compilation.

Type Traits

Type extraction technology is a common technology in generic programming. Its thinking core is: Wrap a series of related nature to a single Class, so we can get some required and should be obtained during compilation. Type related things. In fact, this idea is a famous proverb in the software field: "Anything can be resolved again by adding additional intermediate levels. By encapsulating the information related to a series of desired types in another type definition, these types can be processed in a consistent manner, providing powerful reusability and flexibility.

Type extraction technology is generally used by templates, and the bias techniques are combined together, so they can supplement their huge power. A simple example is given to find out the type extraction technology. Let's take a look at a simple Template Class IS_Pointer in the Boost Library. We need a main version to handle all the cases of the pointer, as well as a offset version, used to process T is the pointer:

Template struct is_pointer {static const bool value = false;

Template struct is_pointer {static const bool value = true;

A simple example is as follows:

Template

Void Func (T Param) {

IF (IS_POINTER :: Value) {

// do something

}

Else {

// do something

}

...

} Through type extraction technology, we can reserve the results of each recursive during compilation, which is used when returning. About these technologies, more in-depth introduction, please refer to the relevant information yourself, not here. In the source code analysis below, the reader will see the actual use of these technologies.

Typelist realization analysis

With the background knowledge above, let's unveil the mystery of Typelist, walk into the source code of Typelist. First, let's take a look at the definition of Typelist.

Typelist definition

In order to be able to do Typelist's operation, an empty type nullType is defined in the Loki library to mark the end of TyPELIST, the definition of NullType and Typelist is as follows:

Class NullType {};

Template Struct Typelist {TypeDef THEAD; TYPEDEF U TAIL;

A method of tail recursion is used for the definition of specification type TypeList:

NullType is a specified TypelSit if t is a specified Typelist, so for any atomic type U, Typelist is a specification Typelist

Typelist used in the Loki library is a standard type of Typelist, which simplifies the operation of Typelist without reducing flexibility. Typelist referred to later in this article is standardized.

How to define a Typelist? For example: contains: CHAR, INT, LONG TYPELSIT. According to the above definition, you can get the following definition form:

Typelist >>; // Note Two> There must be a space, no

// The compiler will consider it ">>" operator

Such a definition method looks more trouble, Luo Wei, in order to simplify the user's use for Typelist, the LOKI library uses a macro defined mode for the size of 1 to 50 Typelist: #define Typelist_1 (T1) :: LOKI :: Typelist #define Typelist_2 (T1, T2) :: Loki :: Typelist #define Typelist_3 (T1, T2, T3) :: LOKI :: Typelist . This way users will be more convenient to use. Typelist Typical Operation Implementation

Understand the definition of Typelist, here we will detail the three typical operations related to TypeList (LENGTH, TYPEAT, and APPEND). Mastering these typical operations, learning other operations will become very easy.

We will explain through an instance to see the actual operation of the compiler. We define a TyPelist that contains two elements: int, long.

TypedEf Typelist_2 (int, long) mytypelist;

At this point, the compiler will generate the following type definition result in the definition of Typelist:

Struct Typelist

{

Typedef long h;

TypeDef NullType T;

}

Struct Typelist >

{

TypeDef int h;

TypeDef Typelist t;

}

Realization of Length - Get the number of elements in Typelist:

Template struct length; // Only declaration, no implementation, if the type incoming type is not Typelsit

// If you create a compile period error

Template <> struct length // The end condition of recursive call, NullType size is 0, which is used

{// template transit and type extraction skills

//

ENUM {Value = 0};

Template // Removable rule definition, using template offsetting and type extraction technology

Struct Length > {enum {value = 1 length :: value};

When you get the number of elements in MyTyPelist through Length : Value, see how the compiler is recursively called according to the rules we specify. First, the compiler will generate the following versions of Length's set:

Struct Length >>>>>

{

Enum {value = 1 length :: value};

}

Struct Length >>>>>>>>

{

Enum {value = 1 length > :: value};

According to the definition of Length end conditions, Length :: Value is equal to 0, so Length > :: value is equal to length :: value 1, that is, 1. By recurring, you can know, Length :: value is also Length >>> :: value is equal to Length > :: value 1, that is, 2 . During the recursive process of the layer, the type extraction technology has been fully reflected. Value is the type-related information we want to get. During the recursive process of each layer, it is reserved by it. TYPEAT - Getting the elements of the given position Template struct typet; // only statement, no implementation, if the incoming

// Type is not Typelsit

// If you create a compile period error

Template

Struct Typeat , 0> // Removable call end condition, if the given position is 0, then

{// Return to the first element in TyPelist

Typedef head result;};

Template

Struct Typeat , i> // uses type extraction technology. Typename keyword

{// uses an entity that tells the compiler is the type.

TypeDef TypeName Typeat :: result result;

Let's take a look at the use of typeat :: Result, have generated those actions. First, the compiler should generate the following type definition according to the recursive rules:

Struct Typeat , 0> {typef long result

}

Struct Typeat >, 1>

{Typeelist , 0> :: result result

}

Obviously TypeDef Typeat , 0> :: result result; is TypeDef long result; so Typeat :: Result is a long type. Similarly, the type extraction technology is fully used in this implementation, but we don't want Value here, but to result.

Append's implementation - Add an element Template Struct Append; // at the end of Typelist, only declaration, no implementation, if

// Type is not Typelsit

// If you create a compile period error

Template <> struct append // recursive end condition definition, bias of the template

{Typedef nulltype result;

Template struct append // recursive end condition definition, bias of templates

{typef typefiPelist_1 (t) Result;}; Template

Struct Append > // recursive end condition definition, Template offset

{TypeDef Typelist result;

Template // Recurns rule definition, note that the return result here is type,

Struct Append , t> // uses type extraction technology. Typename keyword

{// uses an entity that tells the compiler is the type. Template's off

// of

TypeDef Typelist :: Result> Result;};

Similarly, let's take a look at the recursive execution of the compiler when using Append :: result. First look at some type definitions generated by the compiler:

Struct Append

{

TypedEf Typelist_1 (FLOAT) Result

}

Struct Append , float> {typedef typelist :: result> result;

Struct Append >, float>

{typef typefelist , float> :: result> result;

}

After simple replacement, append :: result is equal to:

TypeDef Typelist , float> :: result>;

equal:

TypeEf Typelist :: result>>

equal:

TypeEf Typelist >>

That is: TYPELIST_3 (int, long, float); equivalent to adding a new element float at the end of the original Typelist. Needless to say, the type extraction technology has also played a huge role.

Conclude

This article analyzes the implementation of Typelsit, believes that reader friends have mastered for Typelist meanings and practical techniques. So what is Typelsit? In front of the source code, there is no secret, master Typelist, master the key to understand the Loki library. In the Loki library, you will see Abstract Factory mode, and the Visitor mode is how these generic components are built on Typelsit. Beach your bag, pick up this key, hurry to your "treasure hunt" road (the source code of the Loki library can be downloaded from www.moderncppdesign.com).

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

New Post(0)