summaryrefslogtreecommitdiff
path: root/02-11.md
blob: 5de7745760d816468d3eb7ed7405af6b4b093b0e (plain)
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
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
# Template Functions

- Introduction of templates, which are C++ feature that easily permits the reuse of existing code for new purposes
- Shows how to implement and use the simplest kinds of templates: **template functions**

## Finding the Maximum of Two Numbers

### Finding the Maximum of Two Integers

- Here's a small function that you might write to find the maximum of two integers

```
int maximum(int a, int b){
	if(a > b) return a;
	else return b;
}
```

### Finding the Maximum of Two Doubles

- Here's a small function that you might write to find the maximum of two double numbers

```
int maximum(double a, double b){
	if(a > b) return a;
	else return b;
}
```

### Finding the Maximum of Two Knafns

- Here's a small function that you might write to find the maximum of two knafns

```
int maximum(knafn a, knafn b){
	if(a > b) return a;
	else return b;
}
```

### One Hundred Million Functions...

- Suppose your program uses 100,000,000 different data types, and you need maximum function for each...

### A Template Function for Maximum

- This template function can be used with many data types

```
template<typename Item>
Item maximum(Item a, Item b){
	if(a > b) return a;
	else return b;
}
```

- When you write a template function, you choose a data type for the function to depend upon...
- A template prefix is also needed immediately before the function's implementation

### Using a Template Function

- Once a template function is defined, it may be used with any adequate data type in your program...

```
cout << maximum(1, 2);
cout << maxiumum(1.3, 0.9);
```

## Multi Parameter Templates

```
int array_max(int data[], size_t n){
	size_t i;
	int answer;

	assert(n > 0);
	answer = data[0];
	for(i = 1; i < n; i++){
		if(data[i] > answer) answer = data[i];
	return answer;
}
```

### Solution 1

```
template <typename Item>
Item array_max(Item data[], size_t n){
	size_t i;
	Item answer;

	assert(n > 0);
	answer = data[0];
	for(i = 1; i < n; i++){
		if(data[i] > answer) answer = data[i];
	return answer;
}
```

- What are the problems?
	- `size_t` is not generic, so passing, for example, a `const size_t` will return an error

### Examples

```
const size_t SIZE = 5;
double data[SIZE];
//...

cout << array_max(data, SIZE);
cout << array_max(data, 5);

template <typename Item>
Item array_max(Item data[], size_t n);
```

### Solution 2

```
template <typename Item, typename Sizetype>
Item array_max(Item data[], Sizetype n){
	size_t i;
	Item answer;

	assert(n > 0);
	answer = data[0];
	for(i = 1; i < n; i++){
		if(data[i] > answer) answer = data[i];
	return answer;
}
```

---

# Template Classes

- A template function is a function that depends on an underlying data type
- In a similar way, when a class depends on an underlying data type, the class can be implemented as a **template class**
- For example, a single program can use a bag of integers, and a bag of characters, and a bag of strings, and...
- You do not have to determine the data type of a data structure when developing a code

## Bag Example

### Syntax For Template Classes

```
class bag{
	public:
		typedef int value_type;
		typedef size_t size_type;
		...
```

```
template <typename Item>
class bag{
	public:
		...
}
```

- `template <typename Item>` is the template prefix, and it warns the compiler that the following definition will use an unspecified data type called `Item`

### Template Class Functions

- The bag's `value_type` is now dependent on the `Item` type
- **Outside the template class definition** some rules are required to tell the compiler about the dependency:
	- The template prefix `template <class Item>` is placed immediately before each function prototype and definition
	- Outside the template class definition, each use of the class name (such as `bag`) is changed to the template class name (such as `bag<Item>`)
	- Within a class definition or within a member function, we can still use the bag's type names, such as `value_type` or `size_type`
	- Outside of a member function, to use a type such as `bag<Item>::size_type`, we must add a new keyword `typename`, writing the expression `typename bag<Item>::size_type`

### Example 1

- For our **original class**, the function's implementation began this way:

```
bag operator +(const bag& b1, const bag& b2) ...
```

- For the **template class**, the start of the implementation is shown here:

```
template <class Item>
bag<Item> operator +(const bag<Item>& b1, const bag<Item>& b2);
...
```

### Example 2

```
bag::size_type bag::count(const value_type& target) const;
```

- Outside of a member function, you must put the keyword `typename` in front of any member of a template class is the name of a data type

```
template <class Item>
typename bag<Item>::size_type bag<Item>::count (const Item& target) const;
```

## Summary: Item and typename

|In the original Bag class          |In the template bag class    |
|-----------------------------------|-----------------------------|
|value_type                         |Item                         |
|size_type (inside member function) |size_type                    |
|size_type (outside member function)|typename bag<Item>::size_type|

## Header File Changes

- **In the header file**, you place the documentation and the prototypes of the functions; **then you must include the actual implementations of all the functions**
	- The reason for the requirement is to make the compiler's job simpler
	- **An alternative**: You can keep the implementations in a separate implementation file, but place an `include` directive at the bottom of the header file to pick up these implementations
	- We include the following line at the end of the header file:

```
#include "bag4.template" //Include the implementation
```

## Do Not Place using Directive

- Because a template class has its implementation included in the header file, we must not place any `using` directives in the implementation
- Otherwiser, every program that uses our template class will inadvertently use the `using` directives

## Bag Class Header and Implementation Files

### Header File for the Bag Template Class

```
#ifndef SCU_COEN79_BAG4_H
#define SCU_COEN79_BAG4_H
#include <cstdlib> //Provides size_t

namespace scu_coen79_6A{
	template <class Item>
	class bag{
		public:
			//TYPEDEFS and MEMBER CONSTANTS
			typedef std::size_t size_type;
			static const size_type DEFAULT_CAPACITY = 30;

			//CONSTRUCTORS and DESTRUCTORS
			bag(size_type initial_capacity = DEFAULT_CAPACITY);
			bag(const bag& source);
			~bag();

			//MODIFICATION MEMBER FUNCTIONS
			size_type erase(const Item& target);
			bool erase_one(const Item& target);
			void insert(const Item& entry);
			void operator =(const bag& source);
			void operator +=(const bag& addend);
			void reserve(size_type capacity);

			//CONSTANT MEMBER FUNCTIONS
			size_type count(const Item& target) const;
			Item grab() const;
			size_type size() const {return used;};

		private:
			Item *data;         //Pointer to partially filled dynamic array
			size_type used;     //How much of array is being used
			size_type capacity; //Current capacity of the bag
	};
```

- Inside the template class definition: Compiler knows about the dependency on `Item` type
- Some rules are required outside of the template class definition:
	- `template<class Item>` is placed immediately before each function prototype and definition
	- Each use of the class name is changed to the template class name (`bag<Item>`)
	- We should then include the implementation of the template in the header file (needed by most compilers)
		- Instead of that: we keep the implementation in a separate file

```
//NONMEMBER FUNCTIONS
//originally: bag operator +(const bag& b1, const bag& b2);

template <class Item>
bag<Item operator +(const bag<Item>& b1, const bag<Item>& b2);

#include "bag4.template"
#endif
```

### Implementation File for the Bag Template Class

```
#include <algorithm> //provides copy
#include <cassert>   //provides assert
#include <cstdlib>   //provides rand

namespace SCU_COEN79_6A{

	//MEMBER CONSTANTS
	template <class Item>
	const typename bag<Item>::size_type bag<Item>::DEFAULT_CAPACITY;
```

- Some compilers require the default parameters to be both in the prototype and implementation
- Remeber that:
	- To refer to `size_type` outside a member function: `typename bag<Item>::size_type`
- Each definition is preceded by `template <class Item>`

```
	//CONSTRUCTORS
	template <class Item>