home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!cs.utexas.edu!qt.cs.utexas.edu!yale.edu!yale!mintaka.lcs.mit.edu!ai-lab!life.ai.mit.edu!tmb
- From: tmb@arolla.idiap.ch (Thomas M. Breuel)
- Newsgroups: comp.lang.c++
- Subject: Re: tagged unions, an alternative to RTTI (Re: run-time type checking)
- Message-ID: <TMB.92Jul30152807@arolla.idiap.ch>
- Date: 30 Jul 92 19:28:07 GMT
- References: <1992Jul24.234628.21196@cadsun.corp.mot.com>
- <1992Jul25.172045.24675@ucc.su.OZ.AU> <BryL9q.K5I@watcgl.waterloo.edu>
- <1992Jul28.183746.24287@ucc.su.OZ.AU>
- <TMB.92Jul29125322@arolla.idiap.ch>
- Sender: news@ai.mit.edu
- Reply-To: tmb@idiap.ch
- Followup-To: comp.lang.c++
- Organization: IDIAP (Institut Dalle Molle d'Intelligence Artificielle
- Perceptive)
- Lines: 109
- In-reply-to: tmb@arolla.idiap.ch's message of 29 Jul 92 16:53:22 GMT
-
- I have been asked to post the following response for someone who can't
- post from his site:
-
- From: Deviasse Robert N <a228devi@cdf.toronto.edu>
- Subject: Re: tagged unions, an alternative to RTTI (Re: run-time type checking)
- Newsgroups: comp.lang.c++,comp.std.c++
- In-Reply-To: <TMB.92Jul29125322@arolla.idiap.ch>
- References: <1992Jul24.234628.21196@cadsun.corp.mot.com> <1992Jul25.172045.24675@ucc.su.OZ.AU> <BryL9q.K5I@watcgl.waterloo.edu> <1992Jul28.183746.24287@ucc.su.OZ.AU>
- Organization: University of Toronto Computing Disciplines Facility
-
- Could you post the following to the net (I don't have have write access to
- the net).
-
- Tagged unions may be simulated in C++ by the method described in "The C++
- Programming language 2nd Ed" page 168. The example is good, however, it
- does not deal with the case of what to do if one of the fields in the union
- has a constructor or destructor. If you have access to the class, and can
- separate the struct-part (i.e. static members and functions, nonvirtual
- functions excluding the constructor and destructor) from the class part (i.e.
- the constructor, destructor, and virtual functions), one can work around this
- problem by placing the struct-part in the union and re-attach the class part
- when necessary. This works, however it does not handle cases where this
- separation is not possible. The method below is not much more complicated
- but it should be generally applicable.
-
- Anyway, while modifying a version of XLISP, I decided to add a Complex type
- to the types available to XLISP. The only problem is that, the Complex type
- I have is in a library and has a constructor, thus it cannot be included
- in the union{} describing the XLISP node structure. I got around the problem
- by declaring a char array in the union of size sizeof(Complex) and used
- the necessary casts. It also needed to call the appropriate constructors
- and destructors, It's ugly, but it works.
- Thus (using you syntax):
-
- enum Tag {C,M,I};
- union Eg Tag {
- case C: Complex c; /* Has constructor. */
- case M: Matrix m; /* Has constructor and destructor. */
- case I: int i; /* Has neither. */
- };
-
- would have to be rewritten as:
- (Please forgive any minor typos, I'm writting this from memory.)
-
-
- #define type_cheat(PointerType,pointer) ((PointerType)(void*)(value))
-
- class Eg {
- public:
- enum Tag {C,M,I,UNDEFINED};
- private:
- Tag _tag;
-
- union {
- char _c[sizeof(Complex)];
- char _m[sizeof(Matrix)];
- int _i;
- };
-
- void destroy(){
- switch(tag){
- case C: type_cheat(Complex*,&_c)->Complex::~Complex(); break;
- case M: type_cheat(Matrix*,&_m)->Matrix::~Matrix(); break;
- case I: /* nothing required to be done */ break;
- }
- }
-
- void enTag(Tag tag_){
- if (tag_!=_tag)
- destroy();
- _tag=tag_;
- }
-
- void checkTag(Tag tag_){
- if (tag_!=_tag)
- error();
- }
- public:
- Eg() { _tag=UNDEFINED; }
- ~Eg() { destroy(); }
-
- /* getting member functions */
- Complex c() const { checkTag(C); return *type_cheat(Complex*,&_c); }
- Matrix m() const { checkTag(M); return *type_cheat(Matrix*,&_m); }
- int i() const ( checkTag(I); return _i; }
-
- Tag tag() const { return _tag; }
-
-
- /* setting member functions */
- void c(Complex c_) { enTag(C); new(type_cheat(Complex*,&_c)) Complex(c_); }
- void m(Matrix m_) { enTag(M); new(type_cheat(Matrix*,&_m)) Matrix(m_); }
- void i(int i_) { enTag(I); _i=i_; }
- };
-
-
- Yes, it's verbose, but this is the type of contortions that the compiler
- has to go through if tagged unions were added to C++ -- this is probably
- the reason why tagged unions were not introduced into C++ (besides, what
- is the error() function above, is it an exception, an assert(), ...)
-
- It is possible to use downcasting to solve the above problem (instead of
- using a union, one could derive a ComplexNode, MatrixNode, IntNode from
- a general XLISP_Node), however, this would require a complete rewrite
- of XLISP, particularly the memory manager.
-
- I'll be very interested to know if there is a simpler solution.
- Also, is the above method portable?
-
-