Abstraction: Generic Programming , pt. 2

40
Abstraction: Generic Programming, pt. 2 Templates

description

Abstraction: Generic Programming , pt. 2. Templates. Overloading. Recall overloading Same function name used for different parameter types Compiler decides which function to use according to signature Legal to do in C++, not in C Allows for “generic” programming. Overloading. - PowerPoint PPT Presentation

Transcript of Abstraction: Generic Programming , pt. 2

Page 1: Abstraction: Generic Programming , pt. 2

Abstraction:Generic Programming, pt. 2

Templates

Page 2: Abstraction: Generic Programming , pt. 2

• Recall overloading

Same function name used for different parameter types

Compiler decides which function to use according to signature

• Legal to do in C++, not in C

• Allows for “generic” programming

Overloading

Page 3: Abstraction: Generic Programming , pt. 2

• Recall overloading

Same function name used for different parameter types

Compiler decides which function to use according to signature

• Can also be used with class hierarchy

• Subclass can override superclass function, handle subclass concerns

Overloading

Page 4: Abstraction: Generic Programming , pt. 2

Function Templates

• Acts like a blueprint for instantiating a function

– Type is abstracted in template

– Function is actually instantiated when it is used in program – then and only then is the type determined and bound to the abstract type(s) in the template

– Unlike overloading, the functions with same name are not all written out in code

Page 5: Abstraction: Generic Programming , pt. 2

Function Templates

Two implementations overload compare():int compare (const char &c1, const char &c2){ if (c1 < c2) return -1; if (c2 < c1) return 1; return 0;}

int compare (const int &i1, const int &i2){ if (i1 < i2) return -1; if (i2 < i1) return 1; return 0;}

Page 6: Abstraction: Generic Programming , pt. 2

Function Templates

One function template does the same thing!template <typename T>int compare (const T &v1, const T &v2){ if (v1 < v2) return -1; if (v2 < v1) return 1; return 0;}

Note that the template <typename T> declaration creates a scope in which T is known to the compilerCompare only requires “<” overloading for T

Page 7: Abstraction: Generic Programming , pt. 2

Function Templates

Now compare() can be called on for any two objects for which “<” is defined for their type!

int i1, i2;string s1, s2;double d1, d2;... cout << compare (i1, i2) << endl; // workscout << compare (s1, s2) << endl; // workscout << compare (d1, d2) << endl; // works

Page 8: Abstraction: Generic Programming , pt. 2

Function Templates

Now compare() can be called on for any two objects for which “<” is defined for their type!

When the code with compare is compiled, formal type T is replaced with actual type ...

It is as though you wrote the compare function three (or more) times, once for each type …

… but the compiler does it for you!

Page 9: Abstraction: Generic Programming , pt. 2

Function Templates

Function templates can be declared as

inlineConstexpr

Example:

template <typename T> inline T min(const T&, const T&);

Functions can return template type

Page 10: Abstraction: Generic Programming , pt. 2

Function Templates

Function templates can have multiple formal types

template <typename T, typename U> T fun(const T&, const U&);

Can use either “typename” or “class” - makes no difference

Page 11: Abstraction: Generic Programming , pt. 2

Function Templates

Can have non-type parameters in templates:

template <unsigned N, unsigned M>int compare(const char (&p1)[N], const char (&p2)[M]){ return strcmp(p1, p2);}compare(“Go”, “Gators”)

compiles to:int compare(const char (&p1)[3], const char (&p2)[7])

Page 12: Abstraction: Generic Programming , pt. 2

Function Templates

Compiling the template itself does not generate any code - - only when the function is actually used is code generated- hence function definition is needed in header with template (can't just give declaration)- compiler can only verify that the objects declared with the same formal type are declared with the same actual type when the template is encountered in code

Page 13: Abstraction: Generic Programming , pt. 2

Function Templates

Compiling the template itself does not generate any code - - only when the function is actually used is code generated- most errors only show up after instantiation- compiler can only catch syntax errors in template definition itself- compiler can check number and type agreement of arguments when use is seen- only on instantiation can type-related problems be detected – but where to report the error??? The code is generated!!!

Page 14: Abstraction: Generic Programming , pt. 2

Function Templates

Rules of thumb:- Make as few obligations on the types used as possible (“<” but not “>”, e.g.)- Use const if possible in parameters- When calling, make sure type used satisfies the obligations- A template not used with a type that does not satisfy obligations is NOT a problem!- Do your development with actual types before you convert to templates- Convert incrementally until you become comfortable with the process

Page 15: Abstraction: Generic Programming , pt. 2

Questions?

Page 16: Abstraction: Generic Programming , pt. 2

Class Templates

• Acts like a blueprint for instantiating a class

– Type is abstracted in template

– Compiler cannot deduce the type from use – must declare the type in angle brackets following the template's name

– Types in list are types to use in template formal type list

Page 17: Abstraction: Generic Programming , pt. 2

Class Templates

template <typename T> class Blob {public: typedef T value_type; // for decls typedef typename vector<T>::size_type size_type; Blob(); Blob(initializer_list<T>); size_type size() const {return data->size();} bool empty() const {return data->empty();} void push_back(const T &t) {data->push_back(t);} void pop_back(); T& back(); T& operator[](size_type);private: shared_ptr<vector<T>> data; void check(size_type, const string &msg) const;}

Page 18: Abstraction: Generic Programming , pt. 2

Class Templates

template <typename T> class Blob {public: typedef T value_type; // for decls typedef typename vector<T>::size_type size_type; Blob(); Blob(initializer_list<T>); size_type size() const {return data->size();} bool empty() const {return data->empty();} void push_back(const T &t) {data->push_back(t);} void pop_back(); T& back(); T& operator[](size_type);private: shared_ptr<vector<T>> data; void check(size_type, const string &msg) const;}

value_type is T, which will be declared when Blob is instantiated (as a class) with some

actual type (say, int or string).value_type and size_type are useful for

generic declarations relative to a particularclass without knowing what the details of

the class happen to be

Page 19: Abstraction: Generic Programming , pt. 2

Class Templates

template <typename T> class Blob {public: typedef T value_type; // for decls typedef typename vector<T>::size_type size_type; Blob(); Blob(initializer_list<T>); size_type size() const {return data->size();} bool empty() const {return data->empty();} void push_back(const T &t) {data->push_back(t);} void pop_back(); T& back(); T& operator[](size_type);private: shared_ptr<vector<T>> data; void check(size_type, const string &msg) const;}

Blob has two initializers – one default (for empty blob of desired type) and one with

initializer list (of multiple instances of objects or literals of desired type).

Initializer list can do the things initializer listsdo, like cause the same value to be repeated

N times, or list a bunch of different values.

Page 20: Abstraction: Generic Programming , pt. 2

Class Templates

template <typename T> class Blob {public: typedef T value_type; // for decls typedef typename vector<T>::size_type size_type; Blob(); Blob(initializer_list<T>); size_type size() const {return data->size();} bool empty() const {return data->empty();} void push_back(const T &t) {data->push_back(t);} void pop_back(); T& back(); T& operator[](size_type);private: shared_ptr<vector<T>> data; void check(size_type, const string &msg) const;}

Methods defined inside class template havethe scope of both the class AND the

template,so the class naming scope is assumed, and

the type(s) in the template can be used.

Page 21: Abstraction: Generic Programming , pt. 2

Class Templates

template <typename T> class Blob {public: typedef T value_type; // for decls typedef typename vector<T>::size_type size_type; Blob(); Blob(initializer_list<T>); size_type size() const {return data->size();} bool empty() const {return data->empty();} void push_back(const T &t) {data->push_back(t);} void pop_back(); T& back(); T& operator[](size_type);private: shared_ptr<vector<T>> data; void check(size_type, const string &msg) const;}

The type(s) in the template can be used in the bracketed list of other class templates

or functions

Page 22: Abstraction: Generic Programming , pt. 2

Class Templates

template <typename T> class Blob {public: typedef T value_type; // for decls typedef typename vector<T>::size_type size_type; Blob(); Blob(initializer_list<T>); size_type size() const {return data->size();} bool empty() const {return data->empty();} void push_back(const T &t) {data->push_back(t);} void pop_back(); T& back(); T& operator[](size_type);private: shared_ptr<vector<T>> data; void check(size_type, const string &msg) const;}

shared_ptr<U> is a “safe pointer” (see Ch 12)

that keeps track of how many pointers point to a dynamically allocated object, and delete

it when there are no pointers left.Use <memory> header.

Page 23: Abstraction: Generic Programming , pt. 2

Questions?

Page 24: Abstraction: Generic Programming , pt. 2

Class Templates

template <typename T> bool Blob<T>::empty() const { return data->empty();}

template <typename T>void Blob<T>::check(size_type index, const string &msg) const{ if (index >= data->size()) Throw out_of_range(msg);}

For functions defined outside of class, notonly must you include the class name for

scoping (Blob) with the scope operator (::), but you must also include the

formal type list (<T>) and first declare the whole thing to be a template (as you would

for a non-member function template)

Page 25: Abstraction: Generic Programming , pt. 2

Class Templates

template <typename T> bool Blob<T>::empty() const { return data->empty();}

template <typename T>void Blob<T>::check(size_type index, const string &msg) const{ if (index >= data->size()) Throw out_of_range(msg);}

The check() function serves to make sure an index is safe to use by throwing an

appropriate exception if it is not

Page 26: Abstraction: Generic Programming , pt. 2

Class Templates

template <typename T> T& Blob<T>::back() { check(0, “Back on empty Blob”); return data->back();}

template <typename T>T& Blob<T>::operator[](size_type index){ check(0, “Blob subscript out of range”); return (*data)[i];}

The template type T can be used as the return type, and can have all the usual

modifiers on it, like *, &, const, etc.

Page 27: Abstraction: Generic Programming , pt. 2

Class Templates

template <typename T> T& Blob<T>::back() { check(0, “Back on empty Blob”); return data->back();}

template <typename T>T& Blob<T>::operator[](size_type index){ check(0, “Blob subscript out of range”); return (*data)[i];}

Both back () and subscript [] operator should be overloaded on const so that both

can return values to use when const is needed and when the value is to be changed

Page 28: Abstraction: Generic Programming , pt. 2

Class Templates

template <typename T> Blob<T>::Blob() : data(make_shared<vector<T>>()) {}

template <typename T>Blob<T>::Blob(initializer_list<T> il) : data(make_shared<vector<T>>(il) {}

Both initializers make use of safe pointer structures – shared pointer and instantiation using make_shared so automatic garbage

collection can be done.Typename T is carried forward to the type list

needed by vector when it is “instantiated”

Page 29: Abstraction: Generic Programming , pt. 2

Class Templates

template <typename T> class BlobPtr {public: BlobPtr(): curr(0) {} T& operator*() const { auto p = check(curr, “Dereference past end”); return (*p)[curr]; // (*p) is the vector ... BlobPtr& operator++(); BlobPtr& operator--();

private: shared_ptr<vector<T>> check(size_t, const string&) const; weak_ptr<vector<T>> wptr; size_t curr; // current position in array}

Here we have another class template for pointers to classes instantiated from the

Blob class template.curr keeps track of where we are in the

objectthe pointer is pointing at.

Page 30: Abstraction: Generic Programming , pt. 2

Class Templates

template <typename T> class BlobPtr {public: BlobPtr(): curr(0) {} T& operator*() const { auto p = check(curr, “Dereference past end”); return (*p)[curr]; // (*p) is the vector ... BlobPtr& operator++(); BlobPtr& operator--();

private: shared_ptr<vector<T>> check(size_t, const string&) const; weak_ptr<vector<T>> wptr; size_t curr; // current position in array}

Overloading the dereference operator *Check now returns a shared pointer (safe) so long as it does not point to someplace

off the end of the storage

Page 31: Abstraction: Generic Programming , pt. 2

Class Templates

template <typename T> class BlobPtr {public: BlobPtr(): curr(0) {} T& operator*() const { auto p = check(curr, “Dereference past end”); return (*p)[curr]; // (*p) is the vector ... BlobPtr& operator++(); BlobPtr& operator--();

private: shared_ptr<vector<T>> check(size_t, const string&) const; weak_ptr<vector<T>> wptr; size_t curr; // current position in array}

Note that BlobPtr& type for the declarations of ++ and -- operators does NOT require the type parameter list <T> as needed

outside the class declaration

Page 32: Abstraction: Generic Programming , pt. 2

Class Templates

template <typename T> class BlobPtr {public: BlobPtr(): curr(0) {} T& operator*() const { auto p = check(curr, “Dereference past end”); return (*p)[curr]; // (*p) is the vector ... BlobPtr& operator++(); BlobPtr& operator--();

private: shared_ptr<vector<T>> check(size_t, const string&) const; weak_ptr<vector<T>> wptr; size_t curr; // current position in array}

When defined outside the class declaration, they would have to be:

BlobPtr<T>& operator++() {...} BlobPtr<T>& operator--() {...}

Page 33: Abstraction: Generic Programming , pt. 2

Class Templates

Postfix ++ operator defined outside class template body:template <typename T> BlobPtr<T> BlobPtr<T>::operator++(int) { BlobPtr retVal = *this; // remember old value ++*this; // increment value return retVal;}

When defined outside the class declaration, must includetype list for return type as well

as for naming scope

Page 34: Abstraction: Generic Programming , pt. 2

Questions?

Page 35: Abstraction: Generic Programming , pt. 2

Class Template Friends

template <typename> class BlobPtr;template <typename> class Blob;template <typename T>bool operator==(const Blob<T>&, const Blob<T>&);template <typename T> Class Blob {{ friend class BlobPtr<T>; friend bool operator==<T> (const Blob<T>&, const Blob<T>&); ...} Forward declarations needed for

friend declarations in BlobForward declaration needed for

parameters in operator==

Page 36: Abstraction: Generic Programming , pt. 2

Class Template Friends

template <typename> class BlobPtr;template <typename> class Blob;template <typename T>bool operator==(const Blob<T>&, const Blob<T>&);template <typename T> Class Blob {{ friend class BlobPtr<T>; friend bool operator==<T> (const Blob<T>&, const Blob<T>&); ...}

Grants friend access to versions of BlobPtr and operator== instantiated

in same type

Page 37: Abstraction: Generic Programming , pt. 2

Class Template Friends

template <typename> class Blob;template <typename T>ostream& operator<<(ostream&, const Blob<T>&);template <typename T> Class Blob {{ friend ostream& operator<< <T> (ostream&, const Blob<T>&); ...}template <typename T>ostream& operator<<(ostream& os, const Blob<T>& b){ ...}

Forward declaration needed for parameters in operator<<

Typename list does not need “formal types” since it is forward decl

Page 38: Abstraction: Generic Programming , pt. 2

Class Template Friends

template <typename> class Blob;template <typename T>ostream& operator<<(ostream&, const Blob<T>&);template <typename T> Class Blob {{ friend ostream& operator<< <T> (ostream&, const Blob<T>&); ...}template <typename T>ostream& operator<<(ostream& os, const Blob<T>& b){ ...}

Forward declaration of operator<< for friend declaration in class

Page 39: Abstraction: Generic Programming , pt. 2

Class Template Friends

template <typename> class Blob;template <typename T>ostream& operator<<(ostream&, const Blob<T>&);template <typename T> Class Blob {{ friend ostream& operator<< <T> (ostream&, const Blob<T>&); ...}template <typename T>ostream& operator<<(ostream& os, const Blob<T>& b){ ...}

Friend declaration of operator<< with partial specialization in class

Page 40: Abstraction: Generic Programming , pt. 2

Class Template Friends

template <typename> class Blob;template <typename T>ostream& operator<<(ostream&, const Blob<T>&);template <typename T> Class Blob {{ friend ostream& operator<< <T> (ostream&, const Blob<T>&); ...}template <typename T>ostream& operator<<(ostream& os, const Blob<T>& b){ ...}

Definition of operator<< with template type for Blob