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
#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
!:: Loki :: Conversion
// 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
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
// 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
// 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;
}