Template issues

Hi all,

I was wondering if someone could help me with one of the exercises I have for uni,

The program itself works fine, however when I attempted to add a template to the class I keep getting the errors: "Cannot use template 'Bivec<T>' without specifying specialization perameters (Borland Compiler E2102) and "Declaration Terminated Incorrectly" referring to the Bivec class' constructor:

Bivec::Bivec (int lo, int hi, T initial_value): v(hi - lo + 1), low(lo)

Any suggestions most welcome,

Thanks,

Full program 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
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
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>

using namespace std;

class Out_of_bounds
{
  public:
	Out_of_bounds(int elem) : bval(elem) {}
	int badval() const {return bval;}
  private:
  int bval;
};


class Pop_on_empty
{};


template <typename T>
class Bivec
{ public:
	Bivec() {low = 0;}
	Bivec (int lo, int hi, T initial_value);
	void push_back(T);
	void push_front(T);
	T pop_back() throw (Pop_on_empty);
	T pop_front() throw (Pop_on_empty);
	int& operator[](int) throw (Out_of_bounds);
	void display() const;
	bool empty() const {return v.size() == 0; }

	Bivec(const Bivec& bx) { copy(bx); }
	~Bivec() { free(); }
	const Bivec& operator=(const Bivec&);
  private:
	vector<T*> v;
	int low;
	void copy(const Bivec&);
	void free();
};

Bivec::Bivec (int lo, int hi, T initial_value): v(hi - lo + 1), low(lo)
{
	for (int i = 0; i < static_cast<int>(v.size()); i++)
		v[i] = new T(initial_value);
}
template <typename T>

template <typename T>
void Bivec<T>::push_back(T x)
{
	v.push_back(new T(x));
}

template <typename T>
void Bivec<T>::push_front(T x)
{
	v.push_back(new T(NULL));
	/*for (int i = 1; i < static_cast<int>(v.size()); i++)
		v[i] = v[i - 1];*/
		for (int i = v.size() - 1; i > 0; i--)
		v[i] = v[i-1];
	v[0] = new T(x);
	low--;
}

template <typename T>
T Bivec<T>::pop_back() throw (Pop_on_empty)
{
	if (v.empty())
		throw Pop_on_empty();
	else
	{
		T g = *v[v.size() - 1];
		v.pop_back();
		return g;
	}
}

template <typename T>
T Bivec<T>::pop_front() throw (Pop_on_empty)
{
	if (v.empty())
		throw Pop_on_empty();
	else
	{
		T g = *v[0];
		for (int i = 1; i < static_cast<int>(v.size()); i++)
			v[i - 1] = v[i];
		v.pop_back();
		low++;
		return g;
	}
}

template <typename T>
int& Bivec<T>::operator[](int n) throw (Out_of_bounds)
{
	if (n < low || n >= low + static_cast<int>(v.size()))
		throw Out_of_bounds(n);
	return *v[n - low];
}

template <typename T>
void Bivec<T>::display() const
{
	for (int i = 0; i < static_cast<int>(v.size()); i++)
		cout << *v[i] << " ";
	cout << endl;
}

template <typename T>
const Bivec<T>& Bivec<T>::operator=(const Bivec& old)
{
	if (this != &old)
	{
		free();
		copy(old);
	}
	return *this;
}

template <typename T>
void Bivec<T>::copy(const Bivec& old)
{
	v = old.v;
	low = old.low;
	for (int i = 0; i < static_cast<int>(v.size()); i++)
		v[i] = new int(*old.v[i]);
}

template <typename T>
void Bivec<T>::free()
{
	while (v.size() > 0)
	{
		v.pop_back();
	}
}


int main()
{try{	Bivec<int> b1;
	cout << "b1, initially empty: ";
	b1.display();
	for (int i = 0; i < 10; i++)
		b1.push_back(i);
	cout << "b1, after push_backs: ";
	b1.display();
	b1.push_front(66);
	b1.push_front(77);
	cout << "b1, after push_fronts: ";
	b1.display();
	int last = b1.pop_back(), first = b1.pop_front();
	cout << "last was " << last << ", first was " <<  first << endl;
	cout << "b1, after pops: ";
	b1.display();
	cout << "b1[-1] " << b1[-1] << ", b1[0] " << b1[0] << ", b1[8] " << b1[8] << endl;
	b1[-1] = 88;
	cout << "b1, after b1[-1] = 88: ";
	b1.display();

	Bivec<int> b2(-5, +5, 0);
	cout << "b2, as constructed: ";
	b2.display();

	Bivec<int> b3(b1);
	cout << "b3, copy-constructed from b1: ";
	b3.display();
	b3 = b2;
	cout << "b3, after b3 = b2: ";
	b3.display();
	cout << "Program should now terminate with exception" << endl;
//	cout << b1[50];	// should throw exception
	while( true )
		b3.pop_back();	// should throw exception

}
catch(const Out_of_bounds& ob)
{	cerr << "Invalid subscript " << ob.badval() << endl;
	exit(1);
}
catch(Pop_on_empty)
{	cerr << "Popping empty Bivec" << endl;
	exit(1);
}
} // matches { before try, needed for Borland 
Last edited on
Just look at the way you have done most of the Bivec class functions
for example this one:
1
2
3
4
5
6
7
8
template <typename T>
void Bivec<T>::free()
{
	while (v.size() > 0)
	{
		v.pop_back();
	}
}


Now look at the way you have done this Bivec constructor
1
2
3
4
5
6
Bivec::Bivec (int lo, int hi, T initial_value): v(hi - lo + 1), low(lo)
{
	for (int i = 0; i < static_cast<int>(v.size()); i++)
		v[i] = new T(initial_value);
}
template <typename T> // and what is this line doing here anyway???? 

Thanks very much, I think I got too attached to the idea of the constructor being different to member functions (all the examples I looked through had the constructor fully defined in the class definition.

Thanks for putting up with my brain freeze :)
Aside:

I see exception specifiers in the code above. These are pretty much deprecated these days, and to my knowledge have been so for some while. They should be avoided!!

From A Pragmatic Look at Exception Specifications
Herb Sutter
First pub: C/C++ Users Journal, 20(7), July 2002.
http://www.gotw.ca/publications/mill22.htm

    Moral #1: Never write an exception specification.

    Moral #2: Except possibly an empty one, but if I were you I’d avoid even that.


Andy
Last edited on
Topic archived. No new replies allowed.