Presentation is loading. Please wait.

Presentation is loading. Please wait.

Templates “Generic Programming” ECE 297. 2 Templates A way to write code once that works for many different types of variables –float, int, char, string,

Similar presentations


Presentation on theme: "Templates “Generic Programming” ECE 297. 2 Templates A way to write code once that works for many different types of variables –float, int, char, string,"— Presentation transcript:

1 Templates “Generic Programming” ECE 297

2 2 Templates A way to write code once that works for many different types of variables –float, int, char, string, List, Vector, … Reference: Problem Solving in C++ by Savitch, Chapter 17

3 Template Functions

4 4 Types & Functions All parameters and local variables in a function must have a type void swap_val (int &a, int &b) { int temp; temp = a; a = b; b = temp; } void swap_val (double &a, double &b) { double temp; temp = a; a = b; b = temp; } OK. Function overloading

5 5 Function Templates Allow you to write “abstract algorithms” –Work for many types template void swap_val (VariableType &a, VariableType &b) { VariableType temp; temp = a; a = b; b = temp; } “template prefix” defines a type parameter Can use that “type parameter” instead of a regular type In the function

6 6 Using a Function Template template void swap_val (VariableType &a, VariableType &b) { VariableType temp; temp = a; a = b; b = temp; } int main () { int i1 = 5, i2 = 10; swap_val (i1, i2); // Compiler will create swap_val float f1 = 1e6, f2 = 2e6; swap_val (f1, f2); // Compiler will create swap_val } Template definition must come before template use

7 7 Using a Function Template #include “swap_val.h” int main () { int i1 = 5, i2 = 10; swap_val (i1, i2); // swap_val created float f1 = 1e6, f2 = 2e6; swap_val (f1, f2); // swap_val created } template void swap_val (VariableType &a, VariableType &b) { VariableType temp; temp = a; a = b; b = temp; } main.cpp swap_val.h

8 8 Restrictions on Swap swap_val (int, int); swap_val (char, char); swap_val (List, List); swap_val (int, float); Works for any one type that has proper (deep copy) operator= template void swap_val (VariableType &a, VariableType &b) { VariableType temp; temp = a; a = b; b = temp; } 

9 9 Generic Minimum template VariableType minimum (VariableType a, VariableType b) { if (a < b) return (a); else return (b); } minimum (int, int); minimum (float, float); minimum (int[20], int[20]); minimum (List, List); minimum (string, string); Works for any type that defines operator< (reasonably)  

10 10 Generic Quicksort void QuickSort (int *A, int left, int right) { int PivotIndex = SelectAndShuffle (A, left, right); if (PivotIndex > left) // Basis QuickSort (A, left, PivotIndex-1); // Recursion if (PivotIndex < right) // Basis QuickSort (A, PivotIndex+1, right); // Recursion } template void QuickSort (Tbase *A, int left, int right) { int PivotIndex = SelectAndShuffle (A, left, right); if (PivotIndex > left) // Basis QuickSort (A, left, PivotIndex-1); // Recursion if (PivotIndex < right) // Basis QuickSort (A, PivotIndex+1, right); // Recursion }

11 11 Generic Quicksort int SelectAndShuffle (int *A, int left, int right) { int i, PivotIndex; PivotIndex = left; for (i = left+1 ; i <= right ; ++i) { if (A[i] <= A[left]) { PivotIndex = PivotIndex + 1; swap_val (A[i], A[PivotIndex]); } swap_val (A[left], A[PivotIndex]); return (PivotIndex); }

12 12 Generic Quicksort template int SelectAndShuffle (Tbase *A, int left, int right) { int i, PivotIndex; PivotIndex = left; for (i = left+1 ; i <= right ; ++i) { if (A[i] <= A[left]) { PivotIndex = PivotIndex + 1; swap_val (A[i], A[PivotIndex]); } swap_val (A[left], A[PivotIndex]); return (PivotIndex); }

13 Template Classes

14 14 Template Classes Can make templated (type-generic) classes –Member functions –Member data Most useful for container classes –Classes that implement basic data structures –List, Vector, Tree (Map), …

15 15 Example: Pair of Data Often useful to store two pieces of data together –key, value in ECE 244 lab5 (binary tree for DNS) used together –string name, int ip (244 lab 5) –Could want: string name, string data –or int key, float data –… Make a class that can store two arbitrary pieces of data –first (any type) –second (any type)

16 16 Generic Pair Class template class MyPair { public: MyPair (Tfirst _first, Tsecond _second); void setFirst (Tfirst _first); void setSecond (Tsecond _second); Tfirst getFirst (); Tsecond getSecond (); private: Tfirst first; Tsecond second; }; In MyPair.h

17 17 Generic Pair Class #include “MyPair.h” int main () { MyPair pair1(1, 2.5); cout << pair1.getFirst() << “ “ << pair1.getSecond();... int first = 1 float second = 2.5 pair1 In main.cpp Creates a variable named pair1 class (type) is MyPair

18 18 Generic Pair Class #include “MyPair.h” int main () { MyPair pair1(1, 2.5); cout << pair1.getFirst() << “ “ << pair1.getSecond(); MyPair tscore ("Your test score", 7.5); cout << tscore.getFirst() << " " << tscore.getSecond() << endl; tscore.setFirst ("Revised test score"); tscore.setSecond (9.5); cout << tscore.getFirst() << " " << tscore.getSecond() << endl; } string first = “Your test score” double second = 7.5 tscore In main.cpp Creates a variable named tscore class (type) is MyPair

19 19 Generic Pair Class #include “MyPair.h” int main () { MyPair pair1(1, 2.5); cout << pair1.getFirst() << “ “ << pair1.getSecond(); MyPair tscore ("Your test score", 7.5); cout << tscore.getFirst() << " " << tscore.getSecond() << endl; tscore.setFirst ("Revised test score"); tscore.setSecond (9.5); cout << tscore.getFirst() << " " << tscore.getSecond() << endl; } 1 2.5 Your test score 7.5 Revised test score 9.5 Program output In main.cpp

20 20 Generic Pair Class template MyPair ::MyPair (Tfirst _first, Tsecond _second) { first = _first; second = _second; } template void MyPair ::setFirst (Tfirst _first) { first = _first; } … // Rest of member function defintitions In MyPair.h Template prefix: tells compiler this is a templated function Class name is MyPair

21 21 Function Definitions – Where? Usually bad style to define all member functions in header file But with templates, compiler must be able to generate class as it sees the specific type to build  Needs to see function definitions as it compiles class instantiations –E.g. MyPair in main.cpp –Need to generate instructions (.o) for MyPair, with a Tfirst = int, and Tsecond = float Easiest to achieve by putting whole class implementation in header file In MyPair.h template MyPair ::MyPair (Tfirst _first, Tsecond _second) { first = _first; second = _second; }... // Rest of class member function definitions #include “MyPair.h” int main () { MyPair pair1(1, 2.5); In main.cpp

22 22 Writing Templates Write code for a specific type first –Debug, test Convert to template –Can get complex / subtle syntax errors

23 STL: Generic Algorithms Using the Standard Template Libraries

24 24 STL Writing templates  fairly hard Using templates easy & productive Standard Template Library –Fast, well-tested implementations of useful algorithms and data structures

25 25 STL References Basic Reference: “Problem Solving in C++” by Savitch, Chapter 18 Detailed reference: cplusplus.comcplusplus.com Really nitty gritty details: “C++ Primer” by Lippman, Lajoie and Moo

26 26 STL Writing templates  fairly hard Using templates easy & productive Standard Template Library –Fast, well-tested implementations of useful algorithms and data structures

27 27 STL: Generic Algorithms #include using namespace std; int main ( ) { double x = 1.1, y = 1.2; double z = max (x, y); int j = 2, k = 3; int i = max (j, k); z = max (i, x); z = max (x, 2); z = max (x, 2.0); } main.cpp // Won’t compile // OK! max (double, double) Useful algorithms that work with many types in template T max (T a, T b) { if (a < b) return (b); else return (a); } // OK  max (int, int)

28 28 STL: Generic Algorithms Also in : min (), sort () Work for any one type that defines < and assignment (operator=) and lots more – see cplusplus.com But I only use the very basic ones

29 STL Container Classes

30 30 STL: Container Classes Most useful part of STL –Data structures that just “contain” some other data type / class –E.g. vector, linked list, binary tree of some type Can use to store any type of data (templated) –Avoids a lot of repetitive coding of linked lists, binary trees, etc.

31 31 Vector Example motivation: –Want to read integers from cin to an array until EOF > 1 -20 3 31 55 –Then pass the array on to the rest of the program to process, print, examine, … –Problem: how big an array should we allocate? int *array = new int[??]; –Don’t know until after the input is read! –Could code up a linked list, load it, count elements, then allocate array, copy data from linked list, delete linked list

32 32 Vector Wouldn’t it be great to have something just like an array that could grow as needed? #include using namespace std; vector get_input ( ) { vector vec; // vector of ints, initially empty int val; cin >> val; while ( !cin.fail() ) { vec.push_back (val); // Add new value to end of vector cin >> val; } return (vec); // Return the whole vector } main.cpp

33 33 Vector: Can Use Like Array #include using namespace std;... int main () { vector in_vals; in_vals = get_input (); for (int i = 0; i < in_vals.size(); i++) cout << in_vals[i] << “ “; cout << endl; for (int i = in_vals.size() – 1; i >= 0; i--) cout << in_vals[i] << “ “; } main.cpp vectors know how many elements they contain. Valid data from index 0 to size()-1 Fast, O(1), random access to any entry How would I print out the vector in reverse order? Input: 1 -20 3 31 55 Output: 1 -20 3 31 55 55 31 3 -20 1

34 34 Slightly Cleaner Version int main () { vector in_vals; in_vals = get_input (); for (int i = 0; i < in_vals.size(); i++) cout << in_vals[i] << “ “; } Compiler will give a type mismatch warning (.size() is unsigned int). Harmless, but I prefer to have no warnings. for (int i = 0; i < (int) in_vals.size(); i++) cout << in_vals[i] << “ “; Will make warning go away for (vector ::size_type i = 0; i < in_vals.size(); i++) cout << in_vals[i] << “ “; C++ purist’s way i now unsigned int  watch out for >= 0 tests

35 35 How Does It Work? Input: vector get_input ( ) { vector vec; // vector of ints, initially empty int val; cin >> val; while ( !cin.fail() ) { vec.push_back (val); // Add new value to end of vector cin >> val; } return (vec); // Return the whole vector } int *array int size int capacity 1 1 -20 2 1 3 31 1 -20 1 33155 481 123450 33155 vec

36 36 Vector: Key Properties Efficient to add elements at end (push_back) –Because when there isn’t enough space it grows the storage quite a bit (usually 2x) –Means even for a large number N of push_back(), we get only a few array copies –O(1) on average Efficient random access to data –Because internally the vector stores the data in an array  operator[ ] can be fast –O(1)

37 37 Handy Constructors #include using namespace std; int main () { vector vec1; // default constructor: size = 0 vector vec2(10); // size = 10, but values unknown vector vec3(10,-1); // size = 10, all values -1 }

38 38 Assignment & Destruction #include using namespace std; int main () { int *a = new int[10]; int *b = new int[10]; vector v1(10), v2(10); a[0] = 2; v1[0] = 2;... a = b; // OK? v1 = v2; // OK? delete[] a; delete[] b; delete v1; // Should I? } No! Shallow copy Yes! Proper deep copy defined in No! defines a destructor; cleans up its internal array

39 39 operator[] #include using namespace std; int main () { vector v1; v1.push_back(-3); v1[0] = -2; // OK? v1[1] = -2; // OK? v1.push_back(-3); v1[1] = -2; // OK? } Yes, entry 0 exists No, can’t create values with [ ] Yes, can create values with push_back() Yes, entry 1 exists now Really bad  out of bounds array access and memory corruption (maybe seg fault, maybe worse!) Most compilers have an option to make vector check the [ ] index value is between 0 and size()-1 and print an error (g++ -D_GLIBCXX_DEBUG) Slows program down  we have turned this on only for the debug configuration of your milestone1 NetBeans project

40 40 Shrinking a vector #include using namespace std; int main () { vector v1; v1.push_back(1); v1.push_back(2); for (int i = 0; i < in_vals.size(); i++) cout << in_vals[i] << “ “; v1.pop_back(); // Removes one entry from end of vector for (int i = 0; i < in_vals.size(); i++) cout << in_vals[i] << “ “; } Output: 1 2 Output: 1

41 41 Vectors should be familiar vector almost same as –Difference: string defines some extra utility functions –Otherwise a string really is a vector Full reference on vector member functions at http://www.cplusplus.com/reference/vector/vector/ http://www.cplusplus.com/reference/vector/vector/


Download ppt "Templates “Generic Programming” ECE 297. 2 Templates A way to write code once that works for many different types of variables –float, int, char, string,"

Similar presentations


Ads by Google