From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,1901f265c928a511 X-Google-Attributes: gid103376,public Path: g2news1.google.com!news1.google.com!news.glorb.com!border1.nntp.dca.giganews.com!border2.nntp.dca.giganews.com!nntp.giganews.com!wn13feed!worldnet.att.net!bgtnsc04-news.ops.worldnet.att.net.POSTED!53ab2750!not-for-mail From: Dave Thompson Newsgroups: comp.lang.ada Subject: Re: Typing in Ada Message-ID: References: X-Newsreader: Forte Agent 1.93/32.576 English (American) MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Date: Thu, 10 Jun 2004 03:01:00 GMT NNTP-Posting-Host: 12.75.199.218 X-Complaints-To: abuse@worldnet.att.net X-Trace: bgtnsc04-news.ops.worldnet.att.net 1086836460 12.75.199.218 (Thu, 10 Jun 2004 03:01:00 GMT) NNTP-Posting-Date: Thu, 10 Jun 2004 03:01:00 GMT Organization: AT&T Worldnet Xref: g2news1.google.com comp.lang.ada:1352 Date: 2004-06-10T03:01:00+00:00 List-Id: On Tue, 01 Jun 2004 11:26:30 GMT, "Peter C. Chapin" wrote: > tmoran@acm.org wrote in news:XMTuc.35148$n_6.31103@attbi_s53: > > > I assumed by "C" you really meant something newer, like "C++". In "C" > > "the only operations that you can perform on a structure are take its > > address with &, and access one of its members." (The C Programming > > Language, Kernighan and Ritchie). If you are reading the first edition aka "K&R1", that is out of date. Since the early '80s and in particular in C89 and later, you can also assign a (whole, fixed size) struct, and as a logical consequence pass it as an argument (all arguments are by value in C) or return it as a function value. But yes only in C++ can you overload on struct types, or indeed any other. > > In any case, I'd be curious to see how you would write the above in C++. > Sorry I'm only online intermittently so I couldn't download the previous reference in reasonable time. I'm responding on the assumption it manipulates and displays (representations of) polynomials in something like the obviously (to me) implied way. > C++ supports operator overloading as applied to enums. It doesn't have an > exponentiation operator, however, and you can't create new operators so that > would create a technical inconvenience in this case. Off hand I'm not sure You could overload enum varid ^ int exponent, since there would be no use here for the usual C and C++ meaning as exclusive-or, but it has rather low precedence with the other bitwise operators (which can't be changed) hence couldn't be used as conveniently. > how one would create a function template in C++ that could take an > enumeration type and print the names of the enumerators. I wouldn't want to > say it's impossible though. In any case I'm not sure how that's related to > the issue of strong typing. > You can't; enum names are solely compile time in both C and C++, except for nonstandard and (very) platform-dependent debugging. What you can do is a preprocessor trick, something like: #define Vars_List Var1(X) Var1(Y) Var1(Z) #define Var1(id) id , /* in enum definition */ enum Vars { Vars_List }; /* note trailing comma allowed in C99, in unextended C89 have to hack this slightly or add a dummy name, which can actually be useful anyway for idiomatic half-open [0,N) */ #undef Var1 #define Var1(id) # id , /* in table of names */ const char * Vars_names [] = { Vars_List }; #undef Var1 /* now Y=1 and Vars_names[Y] is the string "Y" etc. */ Alternatively, instead of actual enum values, you could in C++ define and use instances of a class type that collapse into the needed data: class Term { int varid, expon; double factor; public: /*ctor*/ Term (int varid) : varid (varid), expon (1), factor (1.0) { } /* could use a Freevar method that doublechecks varid is in the valid range, known at startup but not compiletime; but if this is made private and the Freevar method a friend, invalid calls are prevented at compile time barring cheating */ Term& operator^= (int expon) { this->expon *= expon; return *this; } Term operator^ (int expon) { Term that (*this); return that ^= expon; } Term& operator*= (double factor) { this->factor *= factor; return *this; } Term operator* (double factor) { Term that (*this); return that *= factor; } }; class Freevar { /*private:*/ typedef std::vector var_names_t; static var_names_t var_names; int varid; public: /*ctor*/ Freevar (const char *this_name) /* save name-string and "return" subscript thereto */ { var_names_t::iterator new_item = var_names.insert (var_names.end(), this_name); this->varid = new_item - var_names.begin(); } static const char * get_name (int id) { return var_names [id]; /* or safer .at(id) */ } /*conversion*/ operator Term () const { return Term (this->varid); } /*converting*/ Term operator^ (int expon) const { return Term (*this) ^ expon; } }; Freevar::var_names_t Freevar::var_names; /* "initialize" */ const Freevar X ("X"); /* gets id 0 */ const Freevar Y ("Y"); /* gets id 1 */ const Freevar Z ("Z"); /* gets id 2 */ /* these particular id values guaranteed only if all (static) definitions in same source file/module; if in separate modules they will be unpredictable but unique, which is enough */ Now Y ^ 3 yields a Term containing an exponent of 3 for id 1, and say Term::output can use Freevar::get_name (1) to get "Y". If you want to do this for multiple "enums" I think you can templatize it but I haven't worked that one out in detail. Or as a real hack you could make the values (singleton instances of) classes that inherit with at least one virtual method, thereby providing RTTI (Run-Time Type Information) whose implementation dependent values you then decode somehow. Yuck. It probably should (but won't) go without saying that this is more work and less simple than built-in compiler support as in Ada. Additional minor point: in C you can't really return a string as a function value. You must either store into a caller-provided buffer; return a pointer to static space (not threadsafe and dubious if used multiple times); or return a pointer to allocated space (caller must free). In C++ you can return a std::string; (in practice though not formally required) this is really a pointer to heap space, but is managed automatically. - David.Thompson1 at worldnet.att.net