Generic Programming Templates Reusability and Genericity Major theme

Generic Programming: Templates

Reusability and Genericity § Major theme in development of programming languages • Reuse code to avoid repeatedly reinventing the wheel § Trend contributing to this • Use of generic code • Can be used with different types of data § Function and class templates • Enable programmers to specify an entire range of related functions and related classes • Generic programming 2

Function Templates (parameterized functions)

Motivation § Initially code was reusable by encapsulating it within functions § Example: • Write void swap (int& first, int& second) { int temp = first; first = second; second = temp; } • Then call swap(x, y);

§ To swap variables of different types, write another function • Overloading allows functions to have same name • Signature (types and numbers of parameters) keep them unique to the compiler § This could lead to a library of swap functions • One function for each standard/primitive type • Compiler chooses which to use from signature void swap (int& first, int& second) { int temp = first; first = second; void swap (double& first, double& second = temp; second) } { double temp = first; void swap (char& first, char& second) first = second; { second = temp; char temp = first; } first = second; second = temp; } § But … what about swapping user defined types such as an object? • We cannot cover the swap function for ALL possible class objects

Passing Types (Instead of Fixed Types) void swap (T& first, T& second) { T temp = first; first = second; second = temp; }

§ Using function overloading, note how similar each of the swap functions would be • The three places where the type is specified § What if we passed the type somehow? § Templates make this possible • Declare functions that receive both data and types via parameter § Thus code becomes more generic • Easier to reuse and extend to other types

Function Templates Produce overloaded functions that perform identical operations/algorithms on different types of data • Programmer writes a single function-template definition • Compiler generates separate object-code functions (functiontemplate specializations) based on argument types in calls to the function template Generate and compile, declaration or definition? compiler does more things …

General Form of Template template<typename T> Function Definition with the parameter type T … § § T is a type-parameter (placeholder) naming the "generic" type of value(s) on which the function operates Function Definition is the definition of the function, using type T Can use ‘class’ or ‘typename’, so it is a type name, so ‘typename’ is better than the old ‘class’!

template<typename T> void swap (T& first, T& second) { T temp = first; first = second; second = temp; } main() { int a, b; double x, y; char m, n; swap(a, b); // swap<int>(a, b); swap(x, y); // swap<double>(x, y); swap(m, n); // swap<char>(m, n); }

Template Instantiation § In and of itself, the template does nothing § When the compiler encounters a template • it stores the template • but doesn't generate any machine instructions or codes § When a function template is instantiated • Compiler finds type parameters in list of function template • For each type in the function parameter list, type of corresponding argument is determined • These two function type and argument type are then bound together § E. g. , when it encounters a call to swap() • Example: swap(int, int); • it generates an integer instance of swap() § The type will be determined … • by the compiler (at compilation time) • from the type of the arguments passed when swap() is called § Cannot specify data type at run time! Static binding!
![Example: displayarray. cpp template <typename T> void display(T array[], int num) { for (int Example: displayarray. cpp template <typename T> void display(T array[], int num) { for (int](http://slidetodoc.com/presentation_image_h2/65ab3f2737736458c0b4b49352f02dae/image-12.jpg)
Example: displayarray. cpp template <typename T> void display(T array[], int num) { for (int i = 0; i < num; i++) cout << array[i] << " "; cout << endl; } int main() { double x[] = {1. 1, 2. 2, 3. 3, 4. 4, 5. 5}; display(x, 5); int num[] = {1, 2, 3, 4}; display(num, 4); } display<double> created display<int> created 1. 1 2. 2 3. 3 4. 4 5. 5 1 2 3 4 § Function-template specializations are generated automatically by the compiler to handle each type of call to the function template § If an array of user-defined objects is used, need to overload << operator of the object class.

When a template type is inside the function … template<typename T> void f() { T a; … } main() { … f(); don’t know? … }; If we cannot deduce the type, we specify it explicitly! main() { … f<int>(); f<doulbe>(); … } It is an implementation choice of the compiler, efficiency …

We can have several different types! template<typename T 1, typename T 2> void f (T 1& first, T 2& second) { } main() { }

Class Templates (parameterized classes)

Motivations: class List { public: List(); List(const list& list); ~List(); bool empty() const; int head() const; void add(int newdata); void delete(); // constructor // copy constructor // destructor // boolean function // access functions // add to the head // delete the head private: … }; List of integer, list of doubles, list of characters, list of objects of any type …

class List { public: List(); List(const List& l); ~List(); bool empty() const; T head() const; void add(T data); void delete(); private: … }; // constructor // copy constructor // destructor // // boolean function access functions add data to the head delete the head

template<typename T> class List { public: List(); List(const List& l); ~list(); bool empty() const; T head() const; void add(T data); void delete(); private: T* head; };

Implementation Some simple member functions: template<typename T> List: : List(){ head=NULL; size=0; } template<typename T> bool List: : empty() const{ } template<typename T> T List: : head() const { }
![Other functions … template<typename T> List: : ~List(){ delete T[] head; } Other functions … template<typename T> List: : ~List(){ delete T[] head; }](http://slidetodoc.com/presentation_image_h2/65ab3f2737736458c0b4b49352f02dae/image-20.jpg)
Other functions … template<typename T> List: : ~List(){ delete T[] head; }

General Form of Class Template template<typename T> class X { … }; X<T> A; List<int> l-int; List<string> lstring; More than one type parameter may be specified: template<typename T 1, . . . , typename Tn> class X { … }; X<T 1, . . . , Tn> B;

Rules For Class Templates § Definitions of member functions outside class declaration must be function templates § All uses of class name as a type must be parameterized with <…> template<typename T> X<T>: : f(…) {…}; (compared to function template, the type is ‘deduced’) § Member functions must be defined in the same file as the class declaration • • Same reason as in function template (i. e. , compiler needs to know the exact data types at calling to generate appropriate object codes at compile time) Sometimes causing inconveniences in makefile (need to combine. h and. cpp) X<T> a, b, c;

How about using ‘typedef’ ? § Old way of doing, in C time § Changes the header file • Any program that uses this must be recompiled inconvenient and timeconsuming § A name declared using typedef can have only one meaning • What if we need two stacks of different types in the same program?

Class template class 1, class 2, class 3, … obj 1, obj 2, obj 3, …

Stack Class Template § Application of all these principles • A Stack class template (Stack. h) • Note that there is not a separate. cpp file § Templates may have more than one type parameter § Thus possible to specify a Stack class differently • Could specify with a dynamic array and pass an integer for the capacity

stacktester 1. cpp Output § Sample Output Pushing elements onto double. Stack 1. 1 2. 2 3. 3 4. 4 5. 5 Stack is full. Cannot push 6. 6 Popping elements from double. Stack 5. 5 4. 4 3. 3 2. 2 1. 1 Stack is empty. Cannot pop Pushing elements onto int. Stack 1 2 3 4 5 6 7 8 9 10 Stack is full. Cannot push 11 Popping elements from int. Stack 10 9 8 7 6 5 4 3 2 1 Stack is empty. Cannot pop

stacktester 2. cpp Sample Output Pushing elements onto double. Stack 1. 1 2. 2 3. 3 4. 4 5. 5 Stack is full. Cannot push 6. 6 Popping elements from double. Stack 5. 5 4. 4 3. 3 2. 2 1. 1 Stack is empty. Cannot pop Pushing elements onto int. Stack 1 2 3 4 5 6 7 8 9 10 Stack is full. Cannot push 11 Popping elements from int. Stack 10 9 8 7 6 5 4 3 2 1 Stack is empty. Cannot pop

Default Types § Type parameters can have default arguments • Template header: template<typename T = string> • Declaration: Stack<> my. String. Stack; // default is string

Other Parameters § Other primitive types (not a generic type) can be parameters of the template • Can have default arguments • Are treated as consts to generate machine codes • Template header: template<typename T, int number> • Declaration: Stack<double, 100> my. Double. Stack;

Templates and Static Members § Each class-template specialization has its own copy of each static data member • All objects of that specialization share that one static data member • static data members must be defined and, if necessary, initialized at file scope § Each class-template specialization gets its own copy of the class template’s static member functions § See special_template. cpp for default and static members

(Explicit) Specializations § Used when a particular type will not work with the general template or requires customized processing § Example for an explicit Stack<Employee> specialization, where Employee is a defined class template<> class Stack<Employee> { // tailor-made implementation here … }; § This is a complete replacement for the general template • This does not use anything from the original class template and can even have different members You can always take control of the specialized classes!!!

Example template<typename T> class X {…}; template<> class X<int> { public: void hello(void); }; // No need to have template<> here void X<int>: : hello(void){ cout << "hello world" << endl; } int main(){ X<int> a; a. hello(); }

Source Code Organization § A template, a declaration or definition? Both? How to separately compile? § The compiler and linker have to make sure the uniqueness of each template instance • So more demanding compilers q Filter out redundant copies … q Find the unique definition … § Different models of instantiations • Repository • Do nothing, put all in *. h, the linker solves the uniqueness q Disadvantage: big amount of code duplication in each translation unit
- Slides: 33