| Title: | C++ |
| Notice: | Read 1.* and use keywords (e.g. SHOW KEY/FULL KIT_CXX_VAX_VMS) |
| Moderator: | DECCXX::AMARTIN |
| Created: | Fri Nov 06 1987 |
| Last Modified: | Thu Jun 05 1997 |
| Last Successful Update: | Fri Jun 06 1997 |
| Number of topics: | 3604 |
| Total number of notes: | 18242 |
I was trying to help a collegue compile a C++ physics simulation code
from UC Berkeley and immediately stumbled into this error given by our
C++ compiler (the original file is actually a .h file, but I named it
list.cxx to simplify things).
I guess this is related to the forward reference to ListIter,
but I'm not very fluent in C++.
The fellow at Berkeley recommended "upgrading" to g++,
as they got much better runtime performance (compared to an old ucode
based DEC C++, I'm expecting a GEM based C++ will do better).
I'd like make this fellow eat his words, but until we can compile this
code, it's rather moot. Will upgrading to the most recent DEC C++
compiler allow this code to compile?
DEC C++, V5.3-004 (CXXBASE530)
Thanks,
John Faricelli
iccad-10> cxx -c list.cxx
cxx: Error: list.cxx, line 69: Type not followed by "(" in an expression.
ListIter<Type> walk(other);
-----------------------------^
cxx: Error: list.cxx, line 78: Type not followed by "(" in an expression.
ListIter<Type>
// -------- CUT HERE --------
#ifndef __List_h
#define __List_h
/*
====================================================================
LIST.H
0.9 (PeterM, 08-93) Original List and Stack classes in G++.
0.961 (PeterM, JohnV, 08-24-93) Replace Borland list containers with
vanilla C++ template lists in list.h
0.964 (JohnV, 09-28-93) Add ListIter::delete() and supporting data.
0.97 (JamesA 12-30-93) Add restart() to ListIter
0.971 (JamesA 02-05-94) Add putAt(), getAt(), find() to List, itemName to ListItem.
0.975 (JamesA 03-12-94) Add removeItem() to List.
(HadonN 06-16-94) Add removeAll(), fix(?) removeItem()
(HadonN 09-19-94) fix(!) removeItem()
0.976 (Hadon 10-20-94) removed putAt(), getAt(), find() from List
0.977 (Hadon 10-28-94) fix operator=(), (call removeAll())
0.978 (JohnV 06-30-95) add deleteAll() to delete all data and remove all items.
0.979 (JohnV 01-11-96) incorporate undocumented additions (from Acquah?)
1.001 (JohnV 02-29-96) renamed N_items() -> nItems().
====================================================================
*/
#include <string.h>
#include <stdlib.h>
template <class Type> class ListItem
{
public:
ListItem(Type *newitem, ListItem<Type> *nxt, const char* key = "") // jbha
{data=newitem; next=nxt; itemName = strdup(key);}
~ListItem() {free(itemName); itemName = NULL; next = NULL; data = NULL;}
/* ~ListItem() { free(itemName); }
deleteData() {delete data; data = NULL; free(itemName); itemName = NULL;}
(commented out 01-11-96 JohnV)
*/
char* itemName; // jbha
ListItem<Type> *next;
Type *data;
};
template <class Type> class List
{
public:
int nitems;
ListItem<Type> *head;
List() {head=0; nitems=0;}
~List() {removeAll();}
void removeItem( Type *anItem);
void removeAll();
void deleteAll();
void add(Type *newitem);
void operator=(List<Type> other)
{
//Not a terribly efficient routine.
//first copy of list is reversed.
//reversed_list goes out of scope and is deleted.
ListIter<Type> walk(other);
List<Type> reversed_list;
removeAll();
while(!walk.Done())
{
reversed_list.add(walk.current());
walk++;
}
ListIter<Type> walk2(reversed_list);
while(!walk2.Done())
{
add(walk2.current());
walk2++;
}
};
Type * pop(void) {
if(head)
{
Type* retval=head->data;
ListItem<Type> *to_delete=head;
head = head->next;
delete to_delete;
nitems--;
return retval;
}
else return 0;
}
int isEmpty() {return (head==0);}
void push(Type *newitem) { add(newitem); };
int nItems() {return nitems;};
};
template <class Type> void List<Type>::add(Type *newitem)
{
ListItem<Type> *New = new ListItem<Type>(newitem, head);
nitems++;
head = New;
}
template <class Type>
void List<Type>::removeItem( Type *anItem )
// use when you need to find the item first, else use version in ListIter
{
ListItem<Type> *prevPtr, *currentPtr;
if (head == NULL) {
return;
} else if (head->data == anItem) {
currentPtr = head->next;
delete head;
head = currentPtr;
nitems--;
} else {
prevPtr = head;
currentPtr = prevPtr->next;
while( !(currentPtr == NULL) ) {
if ( currentPtr->data == anItem ) {
prevPtr->next = currentPtr->next;
delete currentPtr;
currentPtr = prevPtr->next;
nitems--;
} else {
prevPtr = currentPtr;
currentPtr = currentPtr->next;
}
}
}
}
// removeAll: removes all list elements, but NOT the data!
template <class Type>
void List<Type>::removeAll()
{
ListItem<Type> *next;
while (head)
{
next = head->next;
delete head;
head = next;
}
nitems = 0;
}
// deleteAll: removes all list elements AND data
template <class Type>
void List<Type>::deleteAll()
{
ListItem<Type> *next;
while ( head )
{
next = head->next;
delete head->data;
delete head;
head = next;
}
nitems = 0;
}
/*
Acquah's version:
template <class Type>
void List<Type>::deleteAllData()
{
ListItem<Type> *next, *current;
current = head; // necc because deleteData() sometimes
head = NULL; // ... (eventually) calls removeItem()
while ( current )
{
next = (*current).next;
current->deleteData();
delete current;
current = next;
}
nitems = 0;
}
*/
////////////////////////////////////////////////////////////////////////////////
template <class Type> class ListIter
{
public:
ListItem<Type>* currentPtr;
ListItem<Type>* previousPtr;
List<Type>* theList;
ListIter(){} // empty constructor, must be used with restart
ListIter(List<Type>& aList) {theList=&aList; restart();};
void restart() {previousPtr = currentPtr = theList->head;};
void restart(List<Type>& aList) {theList=&aList; restart();};
void restart(Type& aGroup);
Type* data() {if (currentPtr) return currentPtr->data; else return NULL;};
Type* current() {return data();};
void operator++(int) {if (currentPtr) {previousPtr = currentPtr;
currentPtr = currentPtr->next;} else restart();};
int Done() {return currentPtr==NULL;};
int isEmpty() {return !(theList->head==0);};
void deleteCurrent();
};
// This function removes an item from the list. Might be cleaner
// if it is inside List<Type>, but do not want order n search
// for element.
template <class Type>
void ListIter<Type>::deleteCurrent()
{
if (currentPtr == NULL) return; // bail out if empty or at end
// if at head of list, point head to next item
if (currentPtr == theList->head)
{
theList->head = currentPtr->next;
previousPtr = NULL;
}
else previousPtr->next = currentPtr->next;
delete current(); // delete the data
delete currentPtr; // delete the list item
currentPtr = previousPtr;
theList->nitems--;
}
#endif
| T.R | Title | User | Personal Name | Date | Lines |
|---|---|---|---|---|---|
| 3517.1 | the code needs to be reorganized | DECC::J_WARD | Fri Mar 28 1997 09:56 | 255 | |
Since you declare an object of the class Listiter inside List,
you need to move the definition of Listiter before List.
Then add a forward declaration of List before Listiter
since Listiter declares a pointer to List.
Like so:
#ifndef __List_h
#define __List_h
/*
====================================================================
LIST.H
0.9 (PeterM, 08-93) Original List and Stack classes in G++.
0.961 (PeterM, JohnV, 08-24-93) Replace Borland list containers with
vanilla C++ template lists in list.h
0.964 (JohnV, 09-28-93) Add ListIter::delete() and supporting data.
0.97 (JamesA 12-30-93) Add restart() to ListIter
0.971 (JamesA 02-05-94) Add putAt(), getAt(), find() to List, itemName to
ListItem.
0.975 (JamesA 03-12-94) Add removeItem() to List.
(HadonN 06-16-94) Add removeAll(), fix(?) removeItem()
(HadonN 09-19-94) fix(!) removeItem()
0.976 (Hadon 10-20-94) removed putAt(), getAt(), find() from List
0.977 (Hadon 10-28-94) fix operator=(), (call removeAll())
0.978 (JohnV 06-30-95) add deleteAll() to delete all data and remove all items.
0.979 (JohnV 01-11-96) incorporate undocumented additions (from Acquah?)
1.001 (JohnV 02-29-96) renamed N_items() -> nItems().
====================================================================
*/
#include <string.h>
#include <stdlib.h>
template <class T> class List;
template <class Type> class ListItem
{
public:
ListItem(Type *newitem, ListItem<Type> *nxt, const char* key = "") // jbha
{data=newitem; next=nxt; itemName = strdup(key);}
~ListItem() {free(itemName); itemName = NULL; next = NULL; data = NULL;}
/* ~ListItem() { free(itemName); }
deleteData() {delete data; data = NULL; free(itemName); itemName = NULL;}
(commented out 01-11-96 JohnV)
*/
char* itemName; // jbha
ListItem<Type> *next;
Type *data;
};
template <class Type> class ListIter
{
public:
ListItem<Type>* currentPtr;
ListItem<Type>* previousPtr;
List<Type>* theList;
ListIter(){} // empty
constructor, must be used with restart
ListIter(List<Type>& aList) {theList=&aList; restart();};
void restart() {previousPtr = currentPtr = theList->head;};
void restart(List<Type>& aList) {theList=&aList; restart();};
void restart(Type& aGroup);
Type* data() {if (currentPtr) return currentPtr->data; else return
NULL;};
Type* current() {return data();};
void operator++(int) {if (currentPtr) {previousPtr = currentPtr;
currentPtr = currentPtr->next;} else restart();};
int Done() {return currentPtr==NULL;};
int isEmpty() {return !(theList->head==0);};
void deleteCurrent();
};
template <class Type> class List
{
public:
int nitems;
ListItem<Type> *head;
List() {head=0; nitems=0;}
~List() {removeAll();}
void removeItem( Type *anItem);
void removeAll();
void deleteAll();
void add(Type *newitem);
void operator=(List<Type> other)
{
//Not a terribly efficient routine.
//first copy of list is reversed.
//reversed_list goes out of scope and is deleted.
ListIter<Type> walk(other);
List<Type> reversed_list;
removeAll();
while(!walk.Done())
{
reversed_list.add(walk.current());
walk++;
}
ListIter<Type> walk2(reversed_list);
while(!walk2.Done())
{
add(walk2.current());
walk2++;
}
};
Type * pop(void) {
if(head)
{
Type* retval=head->data;
ListItem<Type> *to_delete=head;
head = head->next;
delete to_delete;
nitems--;
return retval;
}
else return 0;
}
int isEmpty() {return (head==0);}
void push(Type *newitem) { add(newitem); };
int nItems() {return nitems;};
};
template <class Type> void List<Type>::add(Type *newitem)
{
ListItem<Type> *New = new ListItem<Type>(newitem, head);
nitems++;
head = New;
}
template <class Type>
void List<Type>::removeItem( Type *anItem )
// use when you need to find the item first, else use version in ListIter
{
ListItem<Type> *prevPtr, *currentPtr;
if (head == NULL) {
return;
} else if (head->data == anItem) {
currentPtr = head->next;
delete head;
head = currentPtr;
nitems--;
} else {
prevPtr = head;
currentPtr = prevPtr->next;
while( !(currentPtr == NULL) ) {
if ( currentPtr->data == anItem ) {
prevPtr->next = currentPtr->next;
delete currentPtr;
currentPtr = prevPtr->next;
nitems--;
} else {
prevPtr = currentPtr;
currentPtr = currentPtr->next;
}
}
}
}
// removeAll: removes all list elements, but NOT the data!
template <class Type>
void List<Type>::removeAll()
{
ListItem<Type> *next;
while (head)
{
next = head->next;
delete head;
head = next;
}
nitems = 0;
}
// deleteAll: removes all list elements AND data
template <class Type>
void List<Type>::deleteAll()
{
ListItem<Type> *next;
while ( head )
{
next = head->next;
delete head->data;
delete head;
head = next;
}
nitems = 0;
}
/*
Acquah's version:
template <class Type>
void List<Type>::deleteAllData()
{
ListItem<Type> *next, *current;
current = head; // necc because
deleteData() sometimes
head = NULL; // ... (eventually)
calls removeItem()
while ( current )
{
next = (*current).next;
current->deleteData();
delete current;
current = next;
}
nitems = 0;
}
*/
////////////////////////////////////////////////////////////////////////////////
// This function removes an item from the list. Might be cleaner
// if it is inside List<Type>, but do not want order n search
// for element.
template <class Type>
void ListIter<Type>::deleteCurrent()
{
if (currentPtr == NULL) return; // bail out if empty or at
end
// if at head of list, point head to next item
if (currentPtr == theList->head)
{
theList->head = currentPtr->next;
previousPtr = NULL;
}
else previousPtr->next = currentPtr->next;
delete current(); //
delete the data
delete currentPtr; //
delete the list item
currentPtr = previousPtr;
theList->nitems--;
}
#endif
| |||||
| 3517.2 | So, is this an extension, or a new lang. feature? | SUBPAC::FARICELLI | Fri Mar 28 1997 11:05 | 10 | |
Thanks. Note that your reply .1 has some lines wrapped in bad places and this causes havoc with the code (puts text after // comments on a new line). So, is this type of forward reference a g++ extension, or something that other C++ compilers (or (proposed) standard) support? -- John | |||||
| 3517.3 | the current language rules... | DECC::J_WARD | Fri Mar 28 1997 12:53 | 40 | |
If we were dealing with ordinary classes, then all compilers would give the error. But we are dealing with templates, and the rules about when error checking is done have only been clarified recently. My undestanding is that according to the C++ draft standard a name within a template definition is looked up at different places depending upon whether or not that name is dependent on a template argument. If "a name does not depend on a template argument, a declaration for that name shall be in scope at the point where the name appears in the template definition." In your example, the name that is not found is: ListIter<T> I think this is considered a dependent name because it uses T, the List template argument. So I don't think name lookup should be done until the point of instantiation, and the error we are issuing is wrong according to these language rules. On the other hand, a name like ListIter<int> would not be dependent on the template parameter T and the compiler would be required to issue an error. I think lots of compilers still have this part wrong (i.e. they err on the favor of not giving diagnostics when they should...) But C++ compilers will differ here ... I found that this version of HP C++ compiler also gives syntax errors - /* <<HP C++ B2402 A.03.50>> */. I'm pretty sure the current Sun C++ compiler gives errors too. Hope I didn't confuse you too much! Judy | |||||