Wide
Believe me: No matter how thick look, if you want is about programming articles, you count to place it. What is discussed herein does not identify a union, and this generic programming part discusses the type of identifiable data. Identification of combination from conceptual synonym: dismantage combination, variable type (variant type), algebraic type, no matter how you call them, identifies United As data abstraction in various It is very useful in applications. Many languages (most of the functional language) is very dependent on the data structure. Maybe you will be used in C in the near future, because ... but what is identifiable, what can I do for you? You will soon find the answer or even more unexpected surprises, but first, you should ask you to make up your article.
A template class called AdhocVisitor is defined for a Template class called AdhocVisitor. This template class does not change the functionality of access to the original level of access to a class level. AdhocVisitor is very simple, assuming you this instantiate: typedef adhocvisitor
If (TextArea * pTextArea = dynamic_cast
As explained in my last article, the method adopted by AdhocVisitor is a phased test to perform a template recursive operation, but the final semantics are the same as the IF-ELSE statement above. Now I want to define a new FormattedTextArea class inherited from Textarea. Very nature, you will add this type to DOCELEMENTVISITOR, so you can also access the FormattedTextArea object:
Typedef adhocvisitor
When visiting DOCELEMENTVISITOR, add Dynamic_cast
A more beautiful solution is to complete this. In fact, Loki has a very good derivedtofront type string to rearrange the type string, which can meet your requirements. You need to view the code of Loki [2] or explain [3] to know the principle, but it is quite simple to use:
Typedef deerivedtofront
These are quite a number of supplements. When writing the last column is fast close to the number limit, I decided to discuss the type string, not some subtle problems across the hierarchy. I do this because Scott Meyers reminded me in a letter: "Too many branches [...] make readers can't completely absorb what you want to say, because they are distracted [...]. Writing I think it is very important to keep concentration. "Sometimes real life is more fun than the best TV series, because the first write letter pointed out that the omission of the previous column is ... SOCTT Meyers he! The second person is UWE BEHRENS. Scott should really get special rewards because he also knows the complete DeriveDTOFRONT solution. Obviously UWE has not read "Modern C Design" [3], otherwise he will be more confident to Adhocvisitor. This can be seen in his comments: "I have used similar mechanisms in my own procedures, including implementation of access mode, in which process, I know a serious defect in this method. I am a painful way I know this (that is, debugging all night). "Summary: bad news is that I have not mentioned an important issue in" Type String and Application "[1], good news is, this issue has an automated solution Scheme [2, 3]. Thank Scott Meyers and Uwe Behrens.
So what is the identification of combination? (Discriminated Unions) Ok, go back to theme. There is already an article about the identifiable union [4] as the foundation of this article you are reading. But that article is smaller, more specialized readers - so many readers ask for more detailed questions. A identifiable combination is a data type that stores a value of a limited set of types and provides access to that type of value. There are some key parts here take special attention. First, the value of the value must be type security, which means that although it looks good, the Observing C is not used here, because it does not provide the value of type security - in other words, it is not recognizable. Union somedata {int aninteger_; double adouble_; char * apoc_;};
The compiler just stores three member variables in overlapping memory, but can't prevent you from illegally using it:
// Take implicit reinterpret_castsomedata dt; dt mpoint_ = "Hello, Cruel World of undiscriminated unions"; int Weird = DT.ANINTEGER;
The second need to point out the scope of the type set. There is an important difference between a complete dynamic polymorphism and identifiable combination. You can view the pointer to the base class as a kind because it can point to an object that inherited from the base class. However, this collection is boundless - you don't know the possible types in advance. Instead, a identifiable combination is only stored only a limited set of possible types, which can be seen when defined. Of course, these types themselves can still be polymorphic. When introducing the Union, most of the C and C books look like a low-level, non-fun tool - "Hey, if you really need to save memory, there is a gadget to you." This is C is all for you. However, it can be identified is a very useful high-level abstraction. This section and the next section of "Wild Programming" will let you believe this.
Applicable use of combination When you need to perform different types of objects (different in status and interfaces) as the same type of object mode (very good in handling different status but uniform interface), you can identify the joint . Assume that the database field value is stored in a data type. The database field can be integer, floating point, string, or date type. There is no common place between these fields in addition to their common in the database. If you want to implement a data structure that can store and operate the database field, you need to store the field type of the database at a particular time. This is where Variants can use. Another example is to store data in dynamic type languages, such as Scheme or Basic language. A variable may be limited, and a small type of type set. Another example is a project that passes to the analyzer. For example, in syntactic analysis, each word you get may be a keyword, which may be an identifier, which may be literal constant (integer, floating point, string, etc.), may be operator, etc. A identifiable combination is the best choice for storing these vocabulary elements. Use a meaningless operation with an object-oriented method, such as a key value for a keyword. In other words, such a categorized method is very bad. As we will see below, as long as you care, you can identify that the combination is huge than other methods (a market person will be "overwhelming") efficiency advantage.
Current implementation of an obvious way to implement identifiable combination in C and C is to use "Tags Union": You store a combination of standards that contain the required types and an integer to display which field is valid, consider the DatabaseField example:
struct DatabaseField {enum TypeTag {typeNull, typeInt, typeDouble, typeString, typeDate} tag_; union {int fieldInt_; double fieldDouble_; char * fieldString_; Date fielddate_;}; ...}; any field whenever you assign a DatabaseField * Member variables, you need to set TAG_ members at the same time. Conversely, before getting a joint member variable, you need to first query TAG_ to know the precise type in the DatabaseField you query. This step can be packaged in a range of Get / Set functions (GetInt, Setint, GetString, SetString, etc.). The problem is, such a method is awkward, there is limited and stiff. You need to manually maintain a three-dimensional relationship - type identity and data plus GET / SET functions. In addition, don't you have a better interface than the clumsy GET / SET function? Implementing a thorough object-oriented method that can identify union is very simple: you inherit all possible types you need from a public category, such as dbfield. This way you have StringDbfield and INTDBFIELD, and more. Your identifiable combination is just a reference to DatabaseField. You use Dynamic_CAST (or corresponding to any statement that calls in your object-oriented language) to get the actual type. This is an object-oriented situation. When your type is almost a matter of operation, it is meaningful to define a class level; however, strings, double precision floating point, integer and date type do not share. A class level cannot effectively express such a structure. You need to depends on type conversions either write a cumbersome function, similar to "Give me the floating point value of that data." This is obviously a bad design.
A modern implementation we have to create an identifiable combination, it has industrial strength, providing almost everything you need, as well as language itself provides these features. First, it will be apparent that a given identifiable combination is only related to the type collection, and we can use the type strings described above. This way, our rough implementation is like this:
Template
You can instantiate VariantTyPedef Variant
Store: Not only about efficiency, how do you want to store actual values in a variant type? The first design can be used to use a union. It is exactly what we need - allows different types of variables to share underlying memory. Plus a small skill, we can take the type from type skewers and put them in the joint. (Do you know if you can template?)
Template
Template
Configurableunion is a union of the type you can do very well control. However, once you want to do this:
Typedef configurableunion
The compiler will remind you that the joint does not accept the type with constructor functions and sectors, which leads to not use for any important program ConfiguRableunion. The second idea is a single storage pointer instead of a direct type and allocating a free storage area for the data. This idea is feasible, but there are two questions: a big problem with a small problem (which small problem is that your opinion is the pureness of the language or the efficiency of execution) One problem is not like this The combination of memory is allocated. Using the free storage area leads to time overhead, there may be spatial overhead (due to the allocator must maintain the data) another more basic (or there is no too much relationship, depending on your opinion) The problem is to change Variant using the free storage area. Exception Guarantees provided by Exception Guarantees. If you allocate memory on site, the constructor of the Variant will only throw the same type of accident, the same type of copy constructor of the incoming type. In particular, if you use a copy that does not give an export type, Variant is also not been thrown. Variant can work well and use unexpected code, and will not have any deviation in unexpected. Use Variant to accidentally simply eat as eating. If we use the free storage area to design Variant, its constructor throws the accident that it stores will be thrown, plus std :: bad_alloc, and even use the "simple" type such as integer or character type to instantiate It may also be thrown out. This is not a good design, because this relaxed Variant may guarantee its customers, and this push will also relax these customers can provide guarantees. Conclusion Yes, Variant is best to allocate memory in place. Let's continue to study this idea of allocating memory, we can use the character cache that does not specify the type, isn't it?
Template
We can actually calculate NEededsize very simply. Just use a recursive algorithm to achieve a maximum element in a type string: you are more than the maximum element of the head and tail (recursive), then you choose two of the big one.
Template
Template <> struct maxsize
template
Template
If you hear a scary loud noise, that is because our current storage is hit on the wall: it can't be used, worse, it can sometimes use some types, in some machines, In some compilers, even with the profit and loss of the moon. Prepare for difficult intervention - we are experiencing an alignment problem. In fact, the problem with our method is what the compiler does not know what we are going to be "real" within Buffer_. The compiler only knows that it must handle a character cache. As a result, in most computer systems, some data types must be stored in a specified offset of memory, such as a typical four-byte integer might allocate an address of four times. This doesn't mean that the eight-byte data must be assigned on an address of eight times - their alignment may also be four (However, no data will require alignment to its own size, because this will destroy the reasons for array of storage rules) It is the physical allocation of memory strips, bus and processor. For example, some memory bars use memory bus low eight bytes, so they cannot directly use the high bytes when they construct them. If you try to get data without correct alignment, you will get one of several possible results. You may get the data you want, but a lot, because the processing is simulated by software rearrangement data, this is the hardware to operate (X86 processor is doing this). However, many other processors, when you try to do illegal address access, will immediately terminate your program. The good news is that you don't have to worry about alignment: the processor has a good handling of this matter by allocating all data allocation. Bad news is that you need to handle it now, because Buffer_ [Neededsize] In fact means you master your destiny. How do we guarantee Buffer_ correct alignment? This is the United Can't do it - it guarantees that its biggest member has enough space and is aligned with the highest membership, which is what we need, so our storage implementation should be like this.
Union {unsigned char buffer_ [needesize]; align dummy_;