"MODERN C ++ Design" source LOKI library reads with sensing 2: type coupled detection and decoupling

zhaozj2021-02-16  53

LOKI library reading: 2 inter-type coupled detection and decoupling

After a long time, I have a feeling of this, I am really embarrassed. The reason is that although I read each line of code of Loki, I really have not understood how to use these code until I have gradually realized.

There are two types of contact between data types: 1. There is an automatic conversion relationship between types; Second, there is a inheritance relationship between types, although it also shows some conversion (mainly object slices and pointer to the presentation) .

So, how do I determine that there is a conversion or inheritage between types? The Loki library Typemanip provides a very beautiful and perfect solution (Note: "More Exceptional C " Item 4 also gives a speech, you can refer.):

// WQ Note: Like the Typelist previously discussed, the Conversion class is also used for compile.

//, so it is solved by providing extraction.

Template

Struct Conversion

{

Typedef Private :: ConversionHelper h;

#ifndef __mwerks__

// WQ Note: This is exquisite! Too long, put it behind.

ENUM {EXISTS = SIZEOF (TypenAme H :: Small) == SizeOf (h :: test (h :: maket ()))};

#ELSE

ENUM {EXISTS = FALSE};

#ENDIF

ENUM {EXISTS2WAY = EXISTS && Conversion :: EXISTS};

ENUM {Sametype = false};

}

// WQ Note: Solve the same type with offsetization

Template

Struct Conversion

{

ENUM {EXISTS = 1, EXISTS2WAY = 1, SameType = 1};

}

// WQ Note: Solution to Void with offsetting and specialization

Template

Struct Conversion

{

ENUM {EXISTS = 1, EXISTS2WAY = 0, Sametype = 0};

}

Template

Struct Conversion

{

ENUM {EXISTS = 1, EXISTS2WAY = 0, Sametype = 0};

}

Template <>

Class Conversion

{

PUBLIC:

ENUM {EXISTS = 1, EXISTS2WAY = 1, SameType = 1};

}

}

First see the definition of the secondary conversionHelper:

Template

Struct ConversionHelper

{

Typedef char small;

Struct Big {char Dummy [2];

// WQ Note: Note that the following three functions have not been implemented!

Static Big Test (...); // WQ Note: In C , no parameters do not require "at least one set of ginseng". Static Small Test (U);

Static t maket ();

}

Look at the Test function, if there is a conversion relationship between T to U, it is sure to adjust the BIG TEST (U) function according to the overload decision. If the return type of two functions is not the same, it can be judged that the version is toned, so it is also possible to speculate whether there is a conversion relationship between T to U.

Turning back and then look at the previous use: sizeof (TypenAme H :: small) == Sizeof (h :: test (h :: maket ()))); because we have talked, Conversion is the class used by the compile period, do not want to adopt The return value is compared to the runtime comparative operation, and there is a SIZEOF () operation to meet the requirements. Therefore, ConversionHelper will implement the return type of the two Test functions in size.

The crash is: Since we only use the size of BIG and SMALL without using its value, you can not create a return object at all, Test functions don't have to be called, so all behaviors are The compilation period. C says that you don't have to create something that is really used, so the test function can not be defined, as long as there is this affirmation. Yes, the LOKI library does not define these three functions! Collapse, crash! Before I don't understand this, I repeatedly searched all the source code and thought I downloaded an incomplete version, then search for the latest version, I have a chaos. Although I don't dare to say that all C compilers can support this, I use the VC, BCB, and DEVCPP three mainstream compilers support this, and the source code of Loki can correctly compile and use.

How to judge that there are two types of inheritance relationships? It is very simple: the derived class pointer type can be automatically mapped to the base class pointer type. Of course, it has to exclude both of the "same type of pointer" and "non-VOID * and VOID *". The LOKI reservoir source code is as follows:

// macro supersubclass

// Invocation: SuperSubclass (B, D) WHERE B and D Are Types.

// Returns True if b IS a public base of d, or if b and d are aliases of the

// Same Type.

//

// Cavet: Might Not Workiffness Inheritance Hierarchy.

#define supersubclass (t, u) /

(: Loki :: Conversion :: exists&& /

!:: Loki :: Conversion :: sametype)

// macro supersubclass_strict

// Invocation: SuperSubclass_strict (b, d) where b and d are type.

// Returns True if b is a public base of d.

//

// Cavet: Might Not Workiffness Inheritance Hierarchy.

#define supersubclass_strict (t, u) /

(SuperSubclass (T, U) && /! :: Loki :: Conversion :: Sametype) // WQ Note: Some people point out that it is best to use const t *, const u *, but indeed T And u is enough, but there may be more points when compiling, and the anti-operating period is not overhead.

The story has not ended, the supplied extracted is int 0 or 1 (of course, it can also be equivalent to BOOL FALSE or TRUE), which can only be operated, so how to compile these results? Loki reservoir has a wonderful solution:

// Class Template INT2TYPE

// Converts Each Integral Constant Into a Unique Type

// Invocation: int2type Where v is a compile-time constant integral

// defines 'Value', An Enum That Evaluates TOV

Template

Struct Int2Type

{

Enum {value = v};

}

// Class Template SELECT

// Selects One of Two Types based Upon A Boolean Constant

// Invocation: Select :: result

// where:

// Flag is a compile-time boolean constant

// T And U Are Types

// Result Evaluates to Ti Flag is true, and to u Otherwise.

Template

Struct SELECT

{

Typedef t result;

}

Template

Struct Select

{

Typedef u results;

}

SELECT, a compile period?: Operation. The compile period can only be derived (template), type decision (overload) to select different branches. INT's 0 and 1 nature are not in these two cases, but int2type <0> and int2type <1> of course are of course satisfied. Relying on the offsetting, SELECT successfully completed its task.

Automatic conversion between types is of course very useful, but many times, it also causes trouble: First, it is easy to generate a multipath, especially when he is inherited; second, the exterior of the expected exterior behavior In particular, the situation is the most confusing at the time of overload;

These three aspects can be avoided in the appropriate time when appropriate.

There are two ways to coupling types: 1. Package with a template; Second, point to the pointer to the pointer.

The implementation of the method is too simple:

Template

Struct Type2Type

{

Typedef t OriginalType;

}

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

New Post(0)