Templates Consider the following function, which swaps two integers: void swap(int &x, int &y) { int temp = x; x = y; y = temp; } int i = 3, j = 4; swap(i,

Slides:



Advertisements
Similar presentations
The C ++ Language BY Shery khan. The C++ Language Bjarne Stroupstrup, the language’s creator C++ was designed to provide Simula’s facilities for program.
Advertisements

This lecture is a bit of a departure in that we’ll cover how C++’s features are actually implemented. This implementation will look suspiciously similar.
Templated Functions. Overloading vs Templating  Overloaded functions allow multiple functions with the same name.
C++ Templates. What is a template? Templates are type-generic versions of functions and/or classes Template functions and template classes can be used.
Pointers Typedef Pointer Arithmetic Pointers and Arrays.
Lecture 18 Templates, Part II. From Last Time: What is a Template? This is the “official” specification for a template. It says that to define a template.
Lecture 3 Feb 4 summary of last week’s topics and review questions (handout) Today’s goals: Chapter 1 overview (sections 1.4 to 1.6) c++ classes constructors,
6/10/2015C++ for Java Programmers1 Pointers and References Timothy Budd.
14 Templates. OBJECTIVES In this chapter you will learn:  To use function templates to conveniently create a group of related (overloaded) functions.
Functions Definition: Instruction block called by name Good design: Each function should perform one task and do it well Functions are the basic building.
Pointers. Topics Pointers Pointer Arithmetic Pointers and Arrays.
Chapter 16 Templates. Copyright © 2006 Pearson Addison-Wesley. All rights reserved Learning Objectives  Function Templates  Syntax, defining 
Run-time type information (RTTI) and casts Consider classes for components and windows: class Component {... virtual void draw() {} }; class Window: public.
Templates. Objectives At the conclusion of this lesson, students should be able to Explain how function templates are used Correctly create a function.
1 Procedural Concept The main program coordinates calls to procedures and hands over appropriate data as parameters.
CSE 332: C++ Classes From Procedural to Object-oriented Programming Procedural programming –Functions have been the main focus so far Function parameters.
Engineering H192 - Computer Programming The Ohio State University Gateway Engineering Education Coalition Lect 28P. 1Winter Quarter Inheritance and Overloading.
CSE 332: C++ templates and generic programming I Motivation for Generic Programming in C++ We’ve looked at procedural programming –Reuse of code by packaging.
CSIS 123A Lecture 12 Templates. Introduction  C++ templates  Allow very ‘general’ definitions for functions and classes  Type names are ‘parameters’
Overview of Previous Lesson(s) Over View  OOP  A class is a data type that you define to suit customized application requirements.  A class can be.
CSE 332: C++ templates This Week C++ Templates –Another form of polymorphism (interface based) –Let you plug different types into reusable code Assigned.
Inheritance. Recall the plant that we defined earlier… class Plant { public: Plant( double theHeight ) : hasLeaves( true ), height (theHeight) { } Plant(
Polymorphism Lecture-10. Print A Cheque A Report A Photograph PrintCheque() PrintReport() PrintPhoto() Printing.
Department of Computer Science and Engineering, HKUST 1 HKUST Summer Programming Course 2008 Templates ~ their instantiation and specialization.
Variables, Functions & Parameter Passing CSci 588 Fall 2013 All material not from online sources copyright © Travis Desell, 2011.
Object Oriented Programming Elhanan Borenstein Lecture #11 copyrights © Elhanan Borenstein.
CSE 332: C++ Type Programming: Associated Types, Typedefs and Traits A General Look at Type Programming in C++ Associated types (the idea) –Let you associate.
Lecture 21 Multiple Inheritance. What is Multiple Inheritance? We defined inheritance earlier in the semester as a relationship between classes. If class.
Week 6 - Wednesday.  What did we talk about last time?  Exam 1!  And before that…  Review!  And before that…  Arrays and strings.
Templates An introduction. Simple Template Functions template T max(T x, T y) { if (x > y) { return x; } else { return y; } } int main(void) { int x =
1 C++ Classes and Data Structures Jeffrey S. Childs Chapter 14 Introduction to Sorting Algorithms Jeffrey S. Childs Clarion University of PA © 2008, Prentice.
1 C++ Classes and Data Structures Jeffrey S. Childs Chapter 5 An Array Class Jeffrey S. Childs Clarion University of PA © 2008, Prentice Hall.
Copyright © Curt Hill Generic Classes Template Classes or Container Classes.
Object-Oriented Programming in C++
Object Oriented Programming Elhanan Borenstein Lecture #10 copyrights © Elhanan Borenstein.
CS 376b Introduction to Computer Vision 01 / 23 / 2008 Instructor: Michael Eckmann.
Computer Programming & Applications Mohamed Iqbal Pallipurath Lecture 02P. 1 Inheritance and Overloading Lecture 28.
C++ How to Program, 9/e © by Pearson Education, Inc. All Rights Reserved.
Lecture 17 Templates, Part I. What is a Template? In short, it’s a way to define generic functionality on parameters without needing to declare their.
Chapter 7 Templates. Objectives Introduction Function Templates Class Templates Standard Template Library.
CPSC 252 The Big Three Page 1 The “Big Three” Every class that has data members pointing to dynamically allocated memory must implement these three methods:
Templates L. Grewe. 2 Goals Often want to do basically the same thing w/diff things –functions work on variables only types specified –  algorithmic.
CSE 332: C++ template examples Concepts and Models Templates impose requirements on type parameters –Types that are plugged in must meet those requirements.
Lecture 19 CIS 208 Wednesday, April 06, Welcome to C++ Basic program style and I/O Class Creation Templates.
1 CSC241: Object Oriented Programming Lecture No 25.
Overview of C++ Templates
CSE 332: C++ Statements C++ Statements In C++ statements are basic units of execution –Each ends with ; (can use expressions to compute values) –Statements.
Fall 2015CISC/CMPE320 - Prof. McLeod1 CISC/CMPE320 Assignment 4 is due Nov. 20 (next Friday). After today you should know everything you need for assignment.
Object-Oriented Programming in C++ Lecture 4 Constants References Operator overloading.
Templates Where the TYPE is generic. Templates for functions Used when the you want to perform the same operation on different data types. The definition.
1 Reference Variables Chapter 8 Page Reference Variables Safer version of C/C++ pointer. "Refers to" a variable. Like a pointer. Effectively.
Cop3530sp12. Parameter passing call by value- appropriate for small objects that should not be altered by the function call by constant reference- appropriate.
Advanced Pointer Topics. Pointers to Pointers u A pointer variable is a variable that takes some memory address as its value. Therefore, you can have.
Pointers & References. Pointers Pointer arithmetic Pointers and arrays Pointer-related typedef’s Pointers and const References.
CSE 332: C++ pointers, arrays, and references Overview of Pointers and References Often need to refer to another object –Without making a copy of the object.
1 Chapter 1 C++ Templates Readings: Sections 1.6 and 1.7.
Chapter 16 Templates Copyright © 2008 Pearson Addison-Wesley. All rights reserved.
Copyright © Curt Hill Generic Functions Separating Data Type from Logic.
Copyright 2006 Pearson Addison-Wesley, 2008, 2012 Joey Paquet 1 Concordia University Department of Computer Science and Software Engineering SOEN6441 –
CSE 332: C++ Exceptions Motivation for C++ Exceptions Void Number:: operator/= (const double denom) { if (denom == 0.0) { // what to do here? } m_value.
Motivation for Generic Programming in C++
Generic Programming in C
C++ Templates.
Motivation and Overview
Inheritance and Overloading
Templates.
CMSC 202 Lesson 22 Templates I.
Templates I CMSC 202.
Templates An introduction.
Templates CMSC 202, Version 4/02.
Presentation transcript:

Templates Consider the following function, which swaps two integers: void swap(int &x, int &y) { int temp = x; x = y; y = temp; } int i = 3, j = 4; swap(i, j);

void swap(int &x, int &y) { int temp = x; x = y; y = temp; } Now suppose we also want a function to swap floats. Then we write another function (we can overload the name “ swap ” for different argument types): void swap(float &x, float &y) { float temp = x; x = y; y = temp; } float f = 4.0, g = 5.0; swap(f, g);

But writing the same code over and over for every possible type can get tiring fast. What we’d really like would be a single swap function that worked for all types. Let’s express what we want as follows: // For any type T, swap two elements of type T: void swap(T &x, T &y) { T temp = x; x = y; y = temp; } swap is supposed to take an two elements of some type (let’s call this type T for the moment), and swap them. But we don’t know what T is when we write swap - ideally, swap should work for all possible types T.

C++ supports template declarations which express exactly what we want: template void swap(T &x, T &y) { T temp = x; x = y; y = temp; } This declares a template function swap which can swap any type. A template is sort of like a function that takes a type as a parameter. The “ class T ” declaration indicates that T is an argument which can be instantiated with any type (despite the name “ class ”, this type can be any type, not just a class type).

template void swap(T &x, T &y) { T temp = x; x = y; y = temp; } swap can be instantiated with different types to produce swap functions specialized to particular types: swap is a function that swaps int s. swap is a function that swaps string s. For example, swap substitutes int for T to produce a function to swap int s: void swap(int &x, int &y) { int temp = x; x = y; y = temp; }

template void swap(T &x, T &y) { T temp = x; x = y; y = temp; } Here’s an example that uses swap to swap a couple of integers, and swap to swap a couple of floating point numbers: int i = 3, j = 4; swap (i, j); float f = 4.0, g = 5.0; swap (f, g);

template void swap(T &x, T &y) { T temp = x; x = y; y = temp; } In practice, C++ can usually infer the right type parameter based on the arguments to a template function: int i = 3, j = 4; swap(i, j); // uses swap float f = 4.0, g = 5.0; swap(f, g); // uses swap

To see how useful templates can be, recall the qsort function in stdlib.h : void qsort(void *base, int num, size_t width, int (*compare)(void *elem1, void *elem2 ) ); This was messy to use because of void*. For instance, our compare function for integers looked like: int compareInt(void *i1Ptr, void *i2Ptr) { if(*((int*)i1Ptr) < *((int*)i2Ptr)) return -1; else if(*((int*)i1Ptr) == *((int*)i2Ptr)) return 0; else return 1; }

We can use templates to get rid of the void*: template void qsort(T *base, int num, int (*compare)(T& elem1, T& elem2 ) ); This declares a template function qsort which can sort any type.

template void qsort(T *base, int num, int (*compare)(T& elem1, T& elem2 ) ); Example (notice that we can write a nice compareInt function without a bunch of casts): int compareInt(int& i1, int& i2) { if(i1 < i2) return -1; else if(i1 == i2) return 0; else return 1; } int iArr[4]; iArr[0] = 3; iArr[1] = 2; iArr[2] = 7; iArr[3] = 5; qsort (iArr, 4, compareInt);

Notice also that the templates enforce a stronger typing property than the void* did: the type of the compare function passed in must match the type of the array. So qsort(iArr, 4, compareInt); typechecks, because compareInt and iArr both are built out of type int. But string sArr[4]; qsort(sArr, 4, compareInt); won’t typecheck, because sArr doesn’t match the type of the compareInt function.

Templates can also be used to create generic data structures. Consider our old FloatArray class, which only worked for elements of type float : class FloatArray { float *arr; int arrSize; public: FloatArray(int size); FloatArray(const FloatArray& from); FloatArray& operator = (const FloatArray& from); ~FloatArray(); float get(int i) const; void set(int i, float f); int size(); };

By declaring and implementing the class as a template, we can make it work for any type: template class TArray { T *arr; int arrSize; public: TArray(int size); TArray(const TArray & from); TArray & operator = (const TArray & from); ~TArray(); T get(int i) const; void set(int i, T f); int size(); }; For example, TArray is a class for an array of float s, and TArray is a class for an array of string s.

template class TArray { T *arr; int arrSize; public: TArray(int size); TArray(const TArray & from); TArray & operator = (const TArray & from); ~TArray(); T get(int i) const; void set(int i, T f); int size(); }; Example: TArray tArr(4); tArr.set(3, 5); int i = tArr.get(3);

template class TArray { T *arr; int arrSize; public: TArray(int size); TArray(const TArray & from); TArray & operator = (const TArray & from); ~TArray(); T get(int i) const; void set(int i, T f); int size(); }; Implementing member functions of a template class: template int TArray ::size() { return arrSize; }

Template functions and template classes can be used together. For instance, the following function sorts a TArray : template void arraysort(TArray &arr, int (*compare)(T& elem1, T& elem2 ) ); Notice again that the element type of the TArray must match the type used by the compare function. Example: TArray tArr(4);... arraysort (tArr, compareInt);

A template can take multiple type arguments: template class Pair { public: T x1; U x2; Pair(T a1, U a2): x1(a1), x2(a2) {} }; Pair p1("deep ", 6); cout << p1.x1 << p1.x2 << endl;

The standard template library There are a number of built-in data structures that are available for you to use, such as list and vector. For instance, list is a list of string s, and vector is a vector of pointers to Shape s. Example: #include using namespace std; // necessary on some platforms list l1; // list of ints vector v1; // vector of pointers to Shapes

2 dimensional arrays can now be implemented as vectors of vectors: vector > arr; Pitfall: the space in “ > > ” is necessary. If you type: vector > arr; then C++ thinks the >> means “right-shift”.

Polymorphism strikes again Remember how inheritance and virtual functions led to a form of polymorphism? A variable of type Shape could hold many different types of objects at run-time ( Circle s, Triangle s, etc.). Templates also provide a form of polymorphism. Inside a template function or class, a variable of type T may refer to many different types of objects, depending on what type T is instantiated with.

Let’s see how these two forms of polymorphism compare. Before templates were introduced into C++, many vendors provided data structure classes based on inheritance. Usually, all elements would have to be derived from a common base class called Object. Then the data structure classes would work with Objects: class Array { Object **arr; public:... Object* get(int i) const; void set(int i, Object* f); };

class Array { Object **arr; public:... Object* get(int i) const; void set(int i, Object* f); }; So if we write a class that inherits from Object, we can put objects of this class into an Array : class MyString: public Object {... }; Array arr(5); arr.set(0, new MyString(“hello”)); arr.set(1, new MyString(“there”));

class Array { Object **arr; public:... Object* get(int i) const; void set(int i, Object* f); }; But if we try to read a MyString object from the array, we find it has type Object* instead of MyString *: Object *o = arr.get(0); So we have to do a cast (yuck!) to make it a MyString* : MyString *m = (MyString *) o;

With templates, we know that the type we get out of a data structure is exactly the type we put into the data structure. So no cast is necessary: template class TArray { T **arr; public:... T* get(int i) const; void set(int i, T* f); }; Array arr(5); arr.set(0, new MyString(“hello”)); arr.set(1, new MyString(“there”)); MyString *m = arr.get(0); // no cast necessary So templates are clearly a nicer, safer way to implement generic data structure classes.

On the other hand, inheritance is the best way to express a common interface shared by a collection of closely related classes. For instance, a collection of shapes can rely on a common base class Shape : class Shape {... public: virtual void draw(); virtual void rotate(double angle); virtual double area(); }; class Circle: public Shape {...}; class Triangle: public Shape {...};

Suppose we didn’t use inheritance to implement shapes, and instead defined each shape independently, without a common base class: class XCircle {... void draw(); void rotate(double angle); double area(); }; class XTriangle {... void draw(); void rotate(double angle); double area(); };

Now suppose we wrote a template function rotateAndDraw, designed to work for XCircle s and XTriangle s: template void rotateAndDraw(T &s, double angle) { s.rotate(angle); s.draw(); } The function assumes that T contains rotate and draw member functions, but it doesn’t document this clearly. For instance, it doesn’t say what argument and return types the rotate and draw functions should have. This is bad style.

It isn’t clear from the template declaration template void rotateAndDraw(T &s, double angle); what types are valid for T. For instance, is an int ok? rotateAndDraw (5, 3.0); // ??? This in fact does not typecheck, because int s don’t have rotate and draw functions. However, we have to look at rotateAndDraw ’s implementation to figure this out. Using inheritance is much better in this case: void rotateAndDraw(Shape &s, double angle) { s.rotate(angle); s.draw(); } Here, the type of s is clearly stated.

Inheritance also allows more heterogeneity. Suppose we want a single list that holds all different kinds of shapes. If shapes aren’t related by inheritance, we can create lists of specific types: list l1; list l2; But l1 can only hold XCircle s, and l2 can only hold XTriangle s. Neither list can hold a mixture of the two. If Circle and Triangle share the base class Shape, though, then list l3; can hold all different kinds of shapes, including Circle s and Triangle s.

Notice that list l3; takes advantage both of templates and inheritance. This combination of templates and inheritance is quite common and very useful. It uses the strengths of templates and inheritance in a complementary way.

Templates: the good, the bad, the ugly good: templates are excellent at expressing generic algorithms and data structures bad and ugly: template implementations go into header files instead of.cpp files template instantiations create multiple copies of a template’s code template uses can’t be typechecked without expanding the entire template

Problem #1: On most platforms, the entire implementation of a template must go in the header file: // swap.h: template void swap(T &x, T &y) { T temp = x; x = y; y = temp; } //.cpp file: #include “swap.h”... This violates everything we’ve told you about source code organization. Usually only declarations go in the header file, and implementations go in a.cpp file.

Problem #2: A different copy of a template’s code is produced for every different type passed in as the templates type parameter. template void qsort(T *base, int num, int (*compare)(T& elem1, T& elem2 ) ); For instance, if the qsort template above is instantiated for int s, float s, and string s, then 3 different copies of qsort ’s code are generated: qsort (...); // generates code for qsort

If the templates are complicated, then this “code bloat” can get quickly out of hand. C++ programmers sometimes complain that their executable files are many megabytes in size because of template instantiation. By contrast, the old qsort in stdlib.h only required one copy of the code, which worked for all types (through the admittedly clunky void* mechanism).

Problem #3: typechecking template instantiations template void rotateAndDraw(T &s, double angle); We’ve already seen the rotateAndDraw example that expects its type T to have rotate and draw member functions. This means that trying to use rotateAndDraw (5, 3.0); won’t typecheck. But how do we know that it won’t typecheck? We have to look through rotateAndDraw ’s implementation, to see what things it does with the objects of type T. This violates the idea of separating the implementation of a function from its interface.

A practical consequence of this is that C++ needs to expand out uses of a template entirely before it can typecheck them. If the template is complicated, This leads to remarkably obscure type errors when something goes wrong. Here’s a small (incorrect) example that uses the standard library class map : map m1; // maps strings to ints // incorrectly tries to insert a pair (“hello”, 6) // into the map: m1.insert(m1.begin(), make_pair("hello", 6)); This incorrectly passes in a char* argument ( “hello” ) to make_pair instead of a string. Let’s see what type error we get.

map m1; // maps strings to ints m1.insert(m1.begin(), make_pair("hello", 6)); Visual Studio 5.0 reports the following type error: error C2664: 'class std::_Tree,class std::allocator >,struct std::pair, class std::allocator >,int>,struct std::map,class std::allocator >,int,struct std::less,class std::allocator >>,class std::allocator >::_Kfn,struct std::less,class std::allocator >>,class std::allocator >::iterator std::map,class std::allocator >,int,struct std::less,class std::allocator >>,class std::allocator >::insert(class std::_Tree,class std::allocator >,struct std::pair,class std::allocator >,int>,struct std::map,class std::allocator >,int,struct std::less,class std::allocator >>,class std::allocator >::_Kfn,struct std::less,class std::allocator >>,class std::allocator >::iterator,const struct std::pair,class std::allocator >,int> &)' : cannot convert parameter 2 from 'struct std::pair ' to 'const struct std::pair,class std::allocator >,int> &'

Don’t be scared off too much by the problems with C++ templates. Templates are still a good idea! But we need to remember that templates are best used for small, simple container classes. Large and complicated templates (such as the map example above) often lead to code bloat and difficult error messages. Simple classes, like list and vector, tend to work very well in practice. We’ll explore these standard library classes in the next lecture.