Problem declaring pointer of netsted class inside template ?

F

flamexx7

Can anybody tell me what is wrong with declaration of pointer p ?

template<class T> class Stack {
struct Link {
T* data;
Link* next;
Link(T* dat, Link* nxt)
: data(dat), next(nxt) {}
}* head;
public:
Stack() : head(0) {}
~Stack();
void push(T* dat) {
head = new Link(dat, head);
}
T* peek() const {
return head ? head->data : 0;
}
T* pop();
// Nested iterator class:
class iterator; // Declaration required
friend class iterator; // Make it a friend
class iterator { // Now define it
Stack::Link* p;
public:
iterator(const Stack<T>& tl) : p(tl.head) {}
// Copy-constructor:
iterator(const iterator& tl) : p(tl.p) {}
// The end sentinel iterator:
iterator() : p(0) {}
// operator++ returns boolean indicating end:
bool operator++() {
if(p->next)
p = p->next;
else p = 0; // Indicates end of list
return bool(p);
}
bool operator++(int) { return operator++(); }
T* current() const {
if(!p) return 0;
return p->data;
}
// Pointer dereference operator:
T* operator->() const {
require(p != 0,
"PStack::iterator::eek:perator->returns 0");
return current();
}
T* operator*() const { return current(); }
// bool conversion for conditional test:
operator bool() const { return bool(p); }
// Comparison to test for end:
bool operator==(const iterator&) const {
return p == 0;
}
bool operator!=(const iterator&) const {
return p != 0;
}
};
iterator begin() const {
return iterator(*this);
}
iterator end() const { return iterator(); }
};

template<class T> Stack<T>::~Stack() {
while(head)
delete pop();
}

template<class T> T* Stack<T>::pop() {
if(head == 0) return 0;
T* result = head->data;
Link* oldHead = head;
head = head->next;
delete oldHead;
return result;
}

int main(){
}
 
V

Victor Bazarov

flamexx7 said:
Can anybody tell me what is wrong with declaration of pointer p ?

What does your compiler say about it? I tested your code with Comeau
online test, and it compiles fine.
template<class T> class Stack {
struct Link {
T* data;
Link* next;
Link(T* dat, Link* nxt)
: data(dat), next(nxt) {}
}* head;
public:
Stack() : head(0) {}
~Stack();
void push(T* dat) {
head = new Link(dat, head);
}
T* peek() const {
return head ? head->data : 0;
}
T* pop();
// Nested iterator class:
class iterator; // Declaration required
friend class iterator; // Make it a friend
class iterator { // Now define it
Stack::Link* p;

I am guessing you're referring to the line above. What is the error
message you get (if any)?
public:
iterator(const Stack<T>& tl) : p(tl.head) {}
// Copy-constructor:
iterator(const iterator& tl) : p(tl.p) {}
// The end sentinel iterator:
iterator() : p(0) {}
// operator++ returns boolean indicating end:
bool operator++() {
if(p->next)
p = p->next;
else p = 0; // Indicates end of list
return bool(p);
}
bool operator++(int) { return operator++(); }
T* current() const {
if(!p) return 0;
return p->data;
}
// Pointer dereference operator:
T* operator->() const {
require(p != 0,
"PStack::iterator::eek:perator->returns 0");
return current();
}
T* operator*() const { return current(); }
// bool conversion for conditional test:
operator bool() const { return bool(p); }
// Comparison to test for end:
bool operator==(const iterator&) const {
return p == 0;
}
bool operator!=(const iterator&) const {
return p != 0;
}
};
iterator begin() const {
return iterator(*this);
}
iterator end() const { return iterator(); }
};

template<class T> Stack<T>::~Stack() {
while(head)
delete pop();
}

template<class T> T* Stack<T>::pop() {
if(head == 0) return 0;
T* result = head->data;
Link* oldHead = head;
head = head->next;
delete oldHead;
return result;
}

int main(){

You might want to try to use your template so that the compiler
actually attempts to instantiate the class.

V
 
D

Daniel T.

"flamexx7 said:
Can anybody tell me what is wrong with declaration of pointer p ?

Stack is a templated type and you don't use the template parameter when
declaring p. Also, Stack<T>::Link is a dependent type, so you have to
use the "typename" keyword. So declare it like this:

typename Stack<T>::Link* p;
 
V

Victor Bazarov

Daniel said:
Stack is a templated type and you don't use the template parameter
when declaring p. Also, Stack<T>::Link is a dependent type, so you
have to use the "typename" keyword. So declare it like this:

typename Stack<T>::Link* p;

Really? Comeau compiles the original program without a peep.

V
 
F

flamexx7

I use Bloodshed 4.9.9.2 and after I applied solution provided by Daniel, my
code compiles fine.
 
F

flamexx7

Ok I found it. It's discuessed in section 14.6 of C++ Standard 2nd edtiion.
So after reading that, I figured out 3 simple ways :-

1. typename Stack<T>::Link* p;

2. We can skip template parametres.
typename Stack::Link* p;

3. We even need to provide name of class in which nested class is declared.
Link* p;
 
V

Victor Bazarov

Daniel said:
Gnu doesn't. I wonder what the standard says...

It's a Gnu's problem. In the original post, 'iterator' is a member,
that means 'Stack' in it refers to the outer template Stack. That
means that Stack::Link is _not_ a dependent name since 'iterator' is
not translated _independently_ of 'Stack'.

V
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,015
Latest member
AmbrosePal

Latest Threads

Top