jamesh@cs.umr.edu (James Hartley) (06/08/91)
I have seen many requests for generic classes, so I am posting my
solution for a parameterized queue class developed with Borland C++ 2.0
via preprocessor tricks. Stacks can likewise be implemented with minimal
changes. Interested readers should refer to _Programming in C++_ by Dew-
hurst & Stark (Prentice-Hall, 1989; ISBN: 0-13-723156-3) pp. 88-91 and
_C++ Primer_ by Lippman (Addison-Wesley, 1989; ISBN: 0-201-16487-6) pp.
145-148. If you have any further questions, feel free to contact me by
email. I will summarize to the newsgroup if sufficient interests exists.
/************************ begin code ***********************************/
// FILE: main.cpp *****
#include <iostream.h>
#include <generic.h>
#include "unqueue.h" // hides needed instantiations
main() {
queue(unsigned) q; // type changed to unsignedqueue by preprocessor
q << 1;
q << 2;
q << 3;
while (!q.empty()) {
unsigned v;
q >> v;
cout << v << " ";
}
cout << "\n";
return 0;
}
// FILE: unqueue.h *****
#ifndef __UNQUEUE_H
# define __UNQUEUE_H
# include <generic.h>
# include "queue.h"
declare(node,unsigned); // preprocessor signal to expand macros
declare(list,unsigned);
declare(queue,unsigned);
#endif
// FILE: queue.h *****
#ifndef __QUEUE_H
# define __QUEUE_H
# include <generic.h>
# include "list.h"
# define queue(TYPE) _Paste2(TYPE,queue) // _Paste2 == name2 of AT&T
# define queuedeclare(TYPE) \
\
class queue(TYPE) : public list(TYPE) { \
void pure() { } /* allows instantiations of class */ \
public: \
boolean operator << (TYPE &v) { return append(v); } \
boolean operator >> (TYPE &v) { return pop(v); } \
};
#endif
// FILE: list.h *****
#ifndef __LIST_H
# define __LIST_H
# include <generic.h>
# include "boolean.h"
# define node(TYPE) _Paste2(TYPE,node)
# define list(TYPE) _Paste2(TYPE,list)
# define listdeclare(TYPE) \
\
class list(TYPE); /* forward reference */ \
\
class node(TYPE) { \
friend class list(TYPE); \
node(TYPE) *next; \
TYPE value; \
node(TYPE)(TYPE &v) { value = v; next = 0; } \
}; \
\
class list(TYPE) { \
node(TYPE) *head, *tail; \
protected: \
list(TYPE)(TYPE &v) { head = tail = new node(TYPE)(v); } \
list(TYPE)() { head = tail = 0; } \
virtual void pure() = 0; /* forces abstract class status */ \
boolean append(TYPE&); \
boolean push(TYPE&); \
boolean pop(TYPE&); \
public: \
boolean empty() { return boolean(head == 0); } \
};
#endif
// FILE: boolean.h *****
#ifndef __BOOLEAN_H
# define __BOOLEAN_H
enum boolean { false, true };
#endif
// FILE: unqueue.cpp *****
#include <generic.h>
#include "unqueue.h"
#include "list.cpp"
implement(list,unsigned); // preprocessor signal to expand macro
// FILE: list.cpp *****
#include "list.h"
#define node(TYPE) _Paste2(TYPE,node)
#define list(TYPE) _Paste2(TYPE,list)
#define listimplement(TYPE) \
\
boolean \
list(TYPE)::append(TYPE &v) { \
node(TYPE) *p = new node(TYPE)(v); \
if (!p) /* check for unsuccessful allocation */ \
return false; \
if (!head) \
head = tail = p; /* first addition of a node to the list */ \
else \
tail = tail->next = p; /* subsequent node additions to list */ \
return true; \
} \
\
boolean \
list(TYPE)::push(TYPE &v) { \
node(TYPE) *p = new node(TYPE)(v); \
if (!p) /* check for unsuccessful allocation */ \
return false; \
if (!head) \
head = tail = p; /* first addition of a node to the list */ \
else { /* subsequent node additions to list */ \
p->next = head; \
head = p; \
} \
return true; \
} \
\
boolean \
list(TYPE)::pop(TYPE &v) { \
if (!head) /* check for empty list */ \
return false; \
v = head->value; \
node(TYPE) *p = head->next; /* retain pointer to 2nd node in list */ \
delete head; /* deallocate spent node */ \
head = p; /* reset head pointer */ \
return true; \
}
/************************** end code ***********************************/
--
James J. Hartley _ /| Internet: jamesh@cs.umr.edu
Department of Computer Science \'o.O' Bitnet: jamesh@cs.umr.edu@umrvmb.bitnet
University of Missouri - Rolla =(___)= UUCP: ...!uunet!cs.umr.edu!jamesh
"Life is like an analogy..." U ACK! PHFFT!miron@cs.sfu.ca (Miron Cuperman) (06/09/91)
Why work hard? There is a cpp with template support at: csc.ti.com:/pub/cpp.tar.Z btw, I just noticed they have a new version. -- By Miron Cuperman <miron@cs.sfu.ca>
sean@ms.uky.edu (Sean Casey) (06/10/91)
miron@cs.sfu.ca (Miron Cuperman) writes: |Why work hard? There is a cpp with template support at: | csc.ti.com:/pub/cpp.tar.Z "With template support" means you can do templates, but it's not standard. Plus there's no directions therein for using the preprocessor with one's favorite compiler. Plus if I read this right, it's an extra step to go through, since the trend is to put the preprocessor in the compiler. I wanted to use cpp to do "standard" templates, but their method didn't meet the Stroustrup model as much as I'd like, so I decided not to use it. Sean -*-*-*-*- On an unrelated note, C++ is giving me headaches. I'm doing my best to write clean, sensible looking code, and it still looks awful when I come back to it. I've been writing C code for 9 years. I can do nice clean work when I want. But a little voice is telling me maybe C++ is a bit too low level for doing lots of OO things. The little voice is telling me to look at Eiffel or some other such entity to write reasonably understood systems. Does that make sense? I wish there were some serious OO design experts around here to consult with. It'd be kind of nice to hear: "Well you're having problems because of the way you designed it." or "You have to tough it out - this kind of problem is just as gnarly in this language as it is in C++." or "Are you crazy? You should be using Smalltalk!" I dunno. Maybe I'll just take more aspirin and type on... Sean -- ** Sean Casey <sean@s.ms.uky.edu>
nagle@well.sf.ca.us (John Nagle) (06/11/91)
The notion that the solution to providing generics in C++ involves a
template preprocessor feeding a C++ preprocessor feeding a C preprocessor
feeding a C compiler leads me to suspect that something is very wrong.
As does the notion that "(void *)" should be a normal part of programming.
John Nagle
jbuck@forney.berkeley.edu (Joe Buck) (06/11/91)
In article <25349@well.sf.ca.us> nagle@well.sf.ca.us (John Nagle) writes: > > The notion that the solution to providing generics in C++ involves a >template preprocessor feeding a C++ preprocessor feeding a C preprocessor >feeding a C compiler leads me to suspect that something is very wrong. I suspect that the people at TI who wrote the thing would agree with you. Think of it as a temporary solution that suffices until compiler vendors support templates. This is equivalent to what the Unix programmer does when he/she prototypes a program by writing a shell script, then later codes it in C or C++ for better efficiency. -- -- Joe Buck jbuck@galileo.berkeley.edu {uunet,ucbvax}!galileo.berkeley.edu!jbuck
al@well.sf.ca.us (Alfred Fontes) (06/11/91)
miron@cs.sfu.ca (Miron Cuperman) writes: >Why work hard? There is a cpp with template support at: > csc.ti.com:/pub/cpp.tar.Z Is there a way to get this without ftp (bbs or mail server, or could someone possibly mail it to me)? Al Fontes, Jr. al@well.sf.ca.us
dag@control.lth.se (Dag Bruck) (06/11/91)
In article <25349@well.sf.ca.us> nagle@well.sf.ca.us (John Nagle) writes: > > The notion that the solution to providing generics in C++ involves a >template preprocessor feeding a C++ preprocessor feeding a C preprocessor >feeding a C compiler leads me to suspect that something is very wrong. To me it suggests that people have successfully managed to build on existing tools. Maybe I would understand your point if you elaborated. -- Dag Bruck
mattel@auto-trol.com (Matt Telles) (06/12/91)
In article <25349@well.sf.ca.us> nagle@well.sf.ca.us (John Nagle) writes: > > As does the notion that "(void *)" should be a normal part of programming. > > John Nagle > > FINALLY! Someone else that dislikes the idea of a pointer to nothing ... Can't we define a type called generic???? (You know, like a generic pointer). Matt -- ============================================================================== Matt Telles mattel@auto-trol.COM {...}ncar!ico!auto-trol!mattel Auto-trol Technology 12500 N Washington Denver, CO 80241-2404 (303)252-2874
chased@rbbb.Eng.Sun.COM (David Chase) (06/12/91)
mattel@auto-trol.com (Matt Telles) writes: >nagle@well.sf.ca.us (John Nagle) writes: >> As does the notion that "(void *)" should be a normal part of programming. > FINALLY! Someone else that dislikes the idea of a pointer to nothing ... >Can't we define a type called generic???? (You know, like a generic pointer). I'm afraid you missed the point. If the only way to write reusable code turns out to be to use "generic" (or "void *") everywhere, what's the point of pretending to have a type checker? People griped about this for Cedar Mesa and Modula-2+, but at least there they had run-time checking of type conversions from generic-to-specific. David Chase Sun
steve@taumet.com (Stephen Clamage) (06/12/91)
mattel@auto-trol.com (Matt Telles) writes: >In article <25349@well.sf.ca.us> nagle@well.sf.ca.us (John Nagle) writes: >> As does the notion that "(void *)" should be a normal part of programming. >> John Nagle > FINALLY! Someone else that dislikes the idea of a pointer to nothing ... >Can't we define a type called generic???? (You know, like a generic pointer). Absolutely!! In fact, we can do this without any changes to the language: typedef void * generic_ptr; Now we can write things like generic_ptr memchr(const generic_ptr ptr, int val, size_t len); which makes it crystal-clear that we are working with generic pointers, not with "pointers to nothing". This is certainly much, much better than having to learn the complicated rule that "void*" means "generic pointer". -- Steve Clamage, TauMetric Corp, steve@taumet.com
gkt@iitmax.iit.edu (George Thiruvathukal) (06/13/91)
In article <1991Jun11.183133.11458@auto-trol.com>, mattel@auto-trol.com (Matt Telles) writes: > FINALLY! Someone else that dislikes the idea of a pointer to nothing ... > Can't we define a type called generic???? (You know, like a generic pointer). > Matt ...or perhaps one could be allowed to declare variables of type void, given its distinguished status as a "scalar" type :-). Then one can declare variables which hold nothing and for which no space is allocated. -- George Thiruvathukal Laboratory for Parallel Computing and Languages Illinois Institute of Technology Chicago
mattel@auto-trol.com (Matt Telles) (06/13/91)
In article <1991Jun12.171947.28079@iitmax.iit.edu> gkt@iitmax.iit.edu (George Thiruvathukal) writes: >In article <1991Jun11.183133.11458@auto-trol.com>, mattel@auto-trol.com (Matt Telles) writes: >> FINALLY! Someone else that dislikes the idea of a pointer to nothing ... >> Can't we define a type called generic???? (You know, like a generic pointer). >> Matt > >...or perhaps one could be allowed to declare variables of type void, given its >distinguished status as a "scalar" type :-). Then one can declare variables >which hold nothing and for which no space is allocated. > >-- >George Thiruvathukal > >Laboratory for Parallel Computing and Languages >Illinois Institute of Technology >Chicago Hey, I LIKE it!! We could call it Write-Only-Memory (or WOM for short)... This could start a whole new programming trend .. non-functional languages... :) (For the humor impaired...) Matt. -- ============================================================================== Matt Telles mattel@auto-trol.COM {...}ncar!ico!auto-trol!mattel Auto-trol Technology 12500 N Washington Denver, CO 80241-2404 (303)252-2874
ttoupin@zephyr.cair.du.edu (Aerin) (06/13/91)
In article <1991Jun12.171947.28079@iitmax.iit.edu> gkt@iitmax.iit.edu (George Thiruvathukal) writes: >In article <1991Jun11.183133.11458@auto-trol.com>, mattel@auto-trol.com (Matt Telles) writes: >> FINALLY! Someone else that dislikes the idea of a pointer to nothing ... >> Can't we define a type called generic???? (You know, like a generic pointer). >> Matt > >...or perhaps one could be allowed to declare variables of type void, given its >distinguished status as a "scalar" type :-). Then one can declare variables >which hold nothing and for which no space is allocated. I like the idea of a generic type (leads to: generic pointers), something like int xxx=3; type thing=xxx, *ptr=&xxx; Then `thing' acts as an <int> type with value `3'. The `type' structure would hold a mangled name for the type it stores; maybe "i" for thing and "Pi" for ptr. A secondary mangled name would be allowed for casting, so that the object doe not loose its integrity after a cast (it still knows that it is a ... when it has been cast to a ...). It would be nice, then, to be able to do something like if(thing==<int>) // something if thing holds an <int> type else if(thing==<float *(*)[]>) // something if thing holds ... THAT In addition, functions should come equipped with two variables, like `this': arguments - an argument list (type arglist) of what the function was called with retval - the return value So, one can do int myprintf(const char *p ...) { if(arguments==<const char *p,float,int *,char []>) // special case... Does something neat :) else printf(p ...); } Or, better yet: myprintf.arguments=<"%s",7.3,&xxx,"blah">; // do something here myprintf.call(); // calls myprintf with preloaded arguments... With preloaded arguments, one might specify arguments to a destructor, among other things. Well, that's my $0.02. Comments? >-- >George Thiruvathukal > >Laboratory for Parallel Computing and Languages >Illinois Institute of Technology >Chicago -- Tory S. Toupin | ttoupin@diana.cair.du.edu | Existence toward perfection... Unversity of Denver | Life of mediocrity! Undergraduate: Math & Computer Sciences| Denver, CO 80208 | - M. E. ----- Ceci n'est pas une signature.
niklas@appli.se (Niklas Hallqvist) (06/15/91)
chased@rbbb.Eng.Sun.COM (David Chase) writes: >mattel@auto-trol.com (Matt Telles) writes: >>nagle@well.sf.ca.us (John Nagle) writes: >>> As does the notion that "(void *)" should be a normal part of programming. >> FINALLY! Someone else that dislikes the idea of a pointer to nothing ... >>Can't we define a type called generic???? (You know, like a generic pointer). >I'm afraid you missed the point. If the only way to write reusable >code turns out to be to use "generic" (or "void *") everywhere, what's >the point of pretending to have a type checker? People griped about >this for Cedar Mesa and Modula-2+, but at least there they had >run-time checking of type conversions from generic-to-specific. Maybe I'm missing the point here too. You still can have a strongly typed language, as long as you carefully encapsulate all type-unsafe casts into small classes where a reader easily can see that you don't lie. Example follows: template<class T> class Stack_of_p : Stack<void*> { public: void push(T* t) { Stack<void*>::push(t); } T* pop() { return (T*)Stack<void*>::pop(); } //... }; It's easy to see that every Stack_of_p<T>::push(T*) implies a cast from T* to void*, and thus the reverse cast in Stack_of_p<T>::pop() is type-safe! (In case the usual stack semantics apply, of course...) Niklas -- Niklas Hallqvist Phone: +46-(0)31-40 75 00 Applitron Datasystem Fax: +46-(0)31-83 39 50 Molndalsvagen 95 Email: niklas@appli.se S-412 63 GOTEBORG, Sweden mcsun!sunic!chalmers!appli!niklas