class within template class problem

Hi, i have an exercise to implement my own list class based on previously created Link class so that in this list class would be iterators and begin() and end() member functions. I will also add my Link class just in case but that is working as far as i know.

Of course I faced a problem when dong this exercise.
When I try to compile this part (lines 30 - 35)
1
2
3
4
5
6
template<class Elem>
list<Elem>::iterator list<Elem>::begin(){
	auto p2 = go_to_first_elem(this->p);
	list<Elem>::iterator iter(p2);
	return iter;
}

I'm getting these compiler errors
Error 3 error C2509: 'begin' : member function not declared in 'list<Elem>'
Error 2 error C2143: syntax error : missing ';' before 'list<Elem>::begin'
Error 4 error C1903: unable to recover from previous error(s); stopping compilation

Anyone can tell me what I did so wrong here?

Here is all list code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
#include "Link.h"
using namespace std;

template<class Elem>
class list{
	//representation and implementation details
	Link<Elem>* p = nullptr;
public:
	list() = default;


	class iterator;

	iterator begin();
	iterator end();

	iterator insert(iterator p, const Elem& v); //insert v into list after p
	iterator erase(iterator p);

	void push_back(const Elem& v);     // insert v at end
	void push_front(const Elem& v);	   // Insert v at front
	void pop_front();		//remove 1st element
	void pop_back();			//remove last element

	Elem& front();		    // the 1st element
	Elem& back();			// the last element
};

template<class Elem>
list<Elem>::iterator list<Elem>::begin(){
	auto p2 = go_to_first_elem(this->p);
	list<Elem>::iterator iter(p2);
	return iter;
}


template<class Elem>
class list<Elem>::iterator{
	Link<Elem>* curr;		//current link
public:
	iterator(Link<Elem>* p) : curr{ p }{}

	iterator& operator++(){ curr = curr->succ; return *this; }
	iterator& operator--(){ curr = curr->prev; return *this; }
	Elem& operator*(){ return curr->value; }   //get value

	bool operator==(const iterator& b) const { return curr == b.curr; }
	bool operator!=(const iterator& b) const{ return curr != b.curr; }
};

My Link.h file but the problem is probably not here
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
#include <iostream>
#include <string>
using namespace std;

template<class T>
void my_swap(T& g1, T& g2){
	T temp = g1;
	g1 = g2;
	g2 = temp;
}

template<class T>
struct Link{
	T value;

	Link(const T& t = T(), Link* p = nullptr, Link* s = nullptr)
		: value(t), prev{ p }, succ{ s }{}

	Link<T>* insert(Link<T>* n);  //insert n before this object
	Link<T>* add(Link<T>* n);     //insert n after this object
	Link<T>* add_ordered(Link<T>* n);
	Link<T>* erase();			//remove this object from list
	Link<T>* find(const T& s);				//find s in list
	const Link* find(const string& s) const;	//find s in const list(see 18.5.1)

	Link<T>* advance(int n) const;			//move n positions in list
	Link<T>* next() const { return succ; }
	Link<T>* previous() const { return prev; }

private:
	Link<T>* prev;
	Link<T>* succ;
};

template<class T>
ostream& operator<<(ostream& os, const Link<T>* lin);

template<class T>
void print_all(Link<T>* p);

template<class T>
Link<T>* Link<T>::insert(Link<T>* n){   //insert n before this object, return n

	if (n == nullptr) return this;
	if (this == nullptr) return n;

	n->succ = this;     //this object comes after n
	if (prev) prev->succ = n;
	n->prev = prev;		//this objectš predecessor becomes n's predecessor
	prev = n;			// n becomes this object's predecessor
	return n;

}

template<class T>
Link<T>* Link<T>::advance(int n) const {
	if (this == nullptr) return nullptr;
	Link<T>* curr = curr = this->succ;
	curr = curr->prev;
	if (0 < n){
		while (n--){
			if (succ == nullptr) return nullptr;
			curr = curr->succ;
		}
	}
	else if (0 > n){
		while (n++){
			if (succ == nullptr) return nullptr;
			curr = curr->prev;
		}
	}
	return curr;
}

template<class T>
Link<T>* Link<T>::add(Link<T>* n){
	//insert n after 'this'
	if (n == nullptr) return this;
	if (this == nullptr) return n;

	n->succ = this->succ;		// n nakamais bus tas kas bija this nakamais
	n->prev = this;				// n ieprieksejais bus this
	if (this->succ){
		this->succ->prev = n;   //ja nakamais aiz this nav 0 , nakama ieprieksejais tagad bus n
	}
	this->succ = n;							//nakamais aiz this bus n


	return n;
}

template<class T>
Link<T>* Link<T>::erase(){
	if (this == nullptr) return nullptr;
	if (this->succ) this->succ->prev = this->prev;
	if (this->prev) this->prev->succ = this->succ;
	if (this->succ) return this->succ;
	else return this->prev;

}

template<class T>
Link<T>* Link<T>::find(const T& s){
	Link<T>* p = this;

	while (p->previous()){
		p = p->previous();
	}
	T val = p->value;
	while (p){
		if (s == val) return p;
		p = p->succ;
	}
	return nullptr;
}

template<class T>
Link<T>* go_to_first_elem(Link<T> *n){
	if (!n){
		if (n->succ())
			n = n->succ();
	}
	else{
		while (n->previous()){
			n = n->previous();
		}
	}
	return n;
}

template<class T>
Link<T>* Link<T>::add_ordered(Link<T>* n){
	T val = n->value;
	//cout << "this = " << this << endl;
	if (!this){ return n; } // ja lists ir tuksh
	else if (this->prev){ // ja this has previous
		this->prev->succ = n;
		n->prev = this->prev;
		this->prev = n;
		n->succ = this;

	}
	else if (!(this->prev)){
		this->prev = n;
		n->succ = this;
		n->prev = nullptr;
	}

	//cout << "\n\n\n";
	n = go_to_first_elem(n);
	//cout << "n = " << n << endl;
	//print_all(n);
	//cout << "\n\n\n";

	//tagad n ir pirmais elements un varam sakt sorting

	int changes_made = 1; // 1 just to enter loop
	while (changes_made){
		//cout << "inside outer loop" << endl;
		changes_made = 0;
		while (n->succ){ //kamer ir nakamais elements
			//cout << "inside inner loop" << endl;
			if (n->value > n->succ->value) {

				//cout << "n = " << n << endl << n->succ << endl << endl;

				my_swap(n->value, n->succ->value);
				changes_made++;
			}
			n = n->succ;
		}
		n = go_to_first_elem(n);
	}
	//cout << "n after = -----------------------" << n << endl;
	//print_all(n); cout << "\n\n\n";
	//tagad atrodam lista to pointeru kuru ielikam lista
	n = n->find(val);
	//cout << "n after =+++++++++++++++++++" << n << endl;
	//print_all(n); cout << "\n\n\n";

	return n;
}


template<class T>
void print_all(Link<T>* p){
	//sakuma aiziesim uz pirmo elementu

	if (!p){ cout << "{ }"; return; }

	while (p->previous()){
		p = p->previous();
	}


	cout << "{ \n";
	while (p){
		cout << p;
		if (p = p->next()) cout << "\n";
	}
	cout << " \n}";
}

template<class T>
ostream& operator<<(ostream& os, const Link<T>* lin){
	if (lin == nullptr) return os;
	os << lin->value;
	return os;
}
Last edited on
The problem is on line 13. That's a forward reference only. On line 39 you try to use an instance of the forward reference which fails. You need to define iterator (line 39) before you can actually instantiate it (line 30).
Tnx a lot for your answer man!
I tried to switch places of iterator and begin() like this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
template<class Elem>
class list{
	//representation and implementation details
	Link<Elem>* p = nullptr;
public:
	list() = default;


	class iterator;

	iterator begin();
	iterator end();

	iterator insert(iterator p, const Elem& v); //insert v into list after p
	iterator erase(iterator p);

	void push_back(const Elem& v);     // insert v at end
	void push_front(const Elem& v);	   // Insert v at front
	void pop_front();		//remove 1st element
	void pop_back();			//remove last element

	Elem& front();		    // the 1st element
	Elem& back();			// the last element
};

template<class Elem>
class list<Elem>::iterator{
	Link<Elem>* curr;		//current link
public:
	iterator(Link<Elem>* p) : curr{ p }{}

	iterator& operator++(){ curr = curr->succ; return *this; }
	iterator& operator--(){ curr = curr->prev; return *this; }
	Elem& operator*(){ return curr->value; }   //get value

	bool operator==(const iterator& b) const { return curr == b.curr; }
	bool operator!=(const iterator& b) const{ return curr != b.curr; }
};

template<class Elem>
list<Elem>::iterator list<Elem>::begin(){
	auto p2 = go_to_first_elem(this->p);
	list<Elem>::iterator iter(p2);
	return iter;
}

I was still getting the same errors.
Did u mean i have to place all the iterator code right inside my list class? I haven't done this with classes but I imagine this should be similar like with function declarations. I declare that there is going to be this class and i can start using it in my code.

I could probably make this (iterator) class outside of list class but what if i don't want to use it outside of link class?

Anyway back to you answer. As far as i understood i had to define this iterator class before i started using it and now i switched definition of it before the code where i started using it. Why is it still giving the same results?

Thanks a lot for your time!
Why is it still giving the same results?
That the compiler doesn't recognize the definiton of iterator has to do with template and that it is actually defined outside the class (the compiler ignores the definition until it's too late).
So yes, if you put the definition of iterator inside the class it should work.

I imagine this should be similar like with function declarations.
Yes.
Sorry for all the questions but is there a way to make this work if i leave the declaration inside list as it is, and write definition some other way so that compiler sees it and can use it when it needs?
Last edited on
Ok, I checked it. I should suffice to write in front of the dependand type iterator the keyword typename:

1
2
3
4
template<class Elem>
typename list<Elem>::iterator list<Elem>::begin(){
...
}
Ohh man, thanks a lot :)
If i may ask where did you check it?
I compiled it with two compiler: gcc and visual c++

visual c++ requires that the definiton of the iterator is placed before the begin() function while gcc does not.
Thank you very much for your effort. Really appreciate! :)
Topic archived. No new replies allowed.