A template class(tstack class) has a singly-linked list "struct" declaration in private section. Another template class(tstackIterator) - iterator class is declared and defined in global space. If the iterator template class trys to get access to the linked list structure inside the previous class with a friend statement declared in the previous class, it does not work. It behaves in much the same way as without friend declaration. The following code shows this: //: TSTACK.H -- Stack using templates #ifndef TSTACK_H_ #define TSTACK_H_ // Some implementations require this: template<class T> class tstackIterator; template<class T> class tstack { struct link { T* data; link* next; link(T* Data, link* Next){ data = Data; next = Next; } } * head; int owns; public: tstack(int Owns = 1) : head(0), owns(Owns) {} ~tstack(); void push(T* Data) { head = new link(Data,head); } T* peek() const { return head->data; } T* pop(); int Owns() const { return owns; } void Owns(int newownership) { owns = newownership; } friend class tstackIterator<T>; }; template<class T> T* tstack<T>::pop() { if(head == 0) return 0; T* result = head->data; link* oldHead = head; head = head->next; delete oldHead; return result; } template<class T> tstack<T>::~tstack() { link* cursor = head; while(head) { cursor = cursor->next; // Conditional cleanup of data: if(owns) delete head->data; delete head; head = cursor; } } template<class T> class tstackIterator { //////////////////////////////////// tstack<T>::link* p; // this is line 68 // when it is compiled, g++ 3.4.1 give some error message but it does not make //sense in terms of languae. but the version g++ (GCC) 3.2.3 20030502 works fine // except that it gives a warning saying "tstack.h:68: warning: `typename //tstack<T>::link' is implicitly a typename" //The Error message is attached to the bottom /////////////////////////////////// public: tstackIterator(const tstack<T>& tl) : p(tl.head) {} tstackIterator(const tstackIterator& tl) : p(tl.p) {} // operator++ returns boolean indicating end: int operator++() { if(p->next) p = p->next; else p = 0; // Indicates end of list return int(p); } int operator++(int) { return operator++(); } // Smart pointer: T* operator->() const { if(!p) return 0; return p->data; } T* current() const { if(!p) return 0; return p->data; } // int conversion for conditional test: operator int() const { return p ? 1 : 0; } }; #endif // TSTACK_H_ //////////////////////////////////////////// the compiler complaints are as follows: In file included from tstktst.cpp:2: ../14/tstack.h:68: error: expected `;' before '*' token ../14/tstack.h: In constructor `tstackIterator<T>::tstackIterator(const tstack<T>&)': ../14/tstack.h:71: error: class `tstackIterator<T>' does not have any field named `p' ../14/tstack.h: In copy constructor `tstackIterator<T>::tstackIterator(const tstackIterator<T>&)': ../14/tstack.h:73: error: class `tstackIterator<T>' does not have any field named `p' ../14/tstack.h: In member function `int tstackIterator<T>::operator++()': ../14/tstack.h:76: error: `p' undeclared (first use this function) ../14/tstack.h:76: error: (Each undeclared identifier is reported only once for each function it appears in.) ../14/tstack.h: In member function `T* tstackIterator<T>::operator->() const': ../14/tstack.h:84: error: `p' undeclared (first use this function) ../14/tstack.h: In member function `T* tstackIterator<T>::current() const': ../14/tstack.h:88: error: `p' undeclared (first use this function) ../14/tstack.h: In member function `tstackIterator<T>::operator int() const': ../14/tstack.h:92: error: `p' undeclared (first use this function)
Not a bug. You have to replace the code at line 68: tstack<T>::link* p; with typename tstack<T>::link* p; Check out the web page <http://gcc.gnu.org/gcc-3.4/changes.html> and search for "You mustnow use the typename and template" ... for more information. There have been a lot of changes to the C++ language since the old days and this is one of them.
Thanks for the reply. In this one line of code tstack<T>::link* p; "tstack<T>::link " is a typename. so I can not give another name. Actually, I got other ways to get around this problem. But I am interested in this style as well. The code I am experimenting came from Bruce Eckel's old book. The 2nd edtion uses a different way from this. Anyway the definition of "tstack<T>::link" is not created inside the class. it is used only to declare a private pointer variable named "head".Actually it is NOT defined. I think that's why g++ (GCC) 3.2.3 20030502 give the warning of "implicite typename". But a new version, g++ 3.4.1, checks it out and send out a error message of "../14/tstack.h:68: error: expected `;' before '*' token". I don't have any idea of what this means. It does not make any sense at all. Would you take a look at it and reply to me ? I really appreciate it in advance. Tyson
The 'typename' keyword is required because later C++ introduces a lot more features. Those that interfere with your code are partial specialization and specialization. For example, you can now have specialization template <> class tstack<bool> { int link; ... }; Then when you declare tstack<bool> t; it will use the above declaration, where 'link' is now a member data instead of a nested class. So the code tstack<T>::link* p; which could be interpreted as declaring a variable which is a pointer to type 'tstack<T>::link' if 'T' is 'int'. But when 'T' is 'bool' it could means multiplying a member data with another variable named 'p'. To resolve the ambiguity, later C++ requires the 'typename' keyword to treat as pointer declaration, otherwise it will be treated as muliplication. Older C++ books don't have this 'typename' keyword but newer good books from respected authors coming out in the last few years should. (Many new C++ books are still wrong). I know the parser error message could be improved, and there are plenty of bug reports elsewhere about it.
Subject: RE: friend funtion inside a template class seems to have a probl Hi lerdsuwa You came up with an interesting topic - class template specializtion. I didn't know aboou it. I need further research on that. As you mentioned, the keyword "typename' is added and compiled and then it works fine. Thanks a lot for your detailed explanation. It haunted me a lot. I was completely stuck for a while even though I found some other ways. Tyson >From: "lerdsuwa at gcc dot gnu dot org" <gcc-bugzilla@gcc.gnu.org> >Reply-To: gcc-bugzilla@gcc.gnu.org >To: max656@hotmail.com >Subject: [Bug c++/19188] friend funtion inside a template class seems to >have a problem >Date: 31 Dec 2004 13:23:03 -0000 > >------- Additional Comments From lerdsuwa at gcc dot gnu dot org >2004-12-31 13:23 ------- >The 'typename' keyword is required because later C++ introduces a lot more >features. Those that interfere with your code are partial specialization >and specialization. For example, you can now have specialization > > template <> class tstack<bool> { > int link; > ... > }; > >Then when you declare > > tstack<bool> t; > >it will use the above declaration, where 'link' is now a member data >instead of a nested class. So the code > > tstack<T>::link* p; > >which could be interpreted as declaring a variable which is a pointer to >type >'tstack<T>::link' if 'T' is 'int'. But when 'T' is 'bool' it could means >multiplying a member data with another variable named 'p'. > >To resolve the ambiguity, later C++ requires the 'typename' keyword to >treat as pointer declaration, otherwise it will be treated as >muliplication. >Older C++ books don't have this 'typename' keyword but newer good books >from respected authors coming out in the last few years should. >(Many new C++ books are still wrong). > >I know the parser error message could be improved, and there are plenty of >bug reports elsewhere about it. > >-- > > >http://gcc.gnu.org/bugzilla/show_bug.cgi?id=19188 > >------- You are receiving this mail because: ------- >You reported the bug, or are watching the reporter.