1 parametric polymorphism polymorphism techniques c++ templates

33
1 Parametric Polymorphism Parametric Polymorphism Polymorphism Techniques C++ Templates

Post on 21-Dec-2015

239 views

Category:

Documents


4 download

TRANSCRIPT

Page 1: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

1

Parametric PolymorphismParametric Polymorphism

Polymorphism Techniques C++ Templates

Page 2: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

2

Polymorphism: OverloadingPolymorphism: Overloading

void f(int n) { cout << n << endl; }

struct Num { Num(int v = 0) : value(v) { } int value; };

void f(Num n) { cout << n.value << endl; }

int main(int, char**) { Num n(5); f(5); f(n); return 0;}

Page 3: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

3

void f(int n) { cout << n << endl; }

struct Num { Num(int v = 0) : value(v) { } int value; operator int() { return value; } };

int main(int, char**) { Num n(5); f(5); f(n); return 0;}

Polymorhism: CoercionPolymorhism: Coercion

Page 4: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

4

struct Num { Num(int v = 0) : value(v) { } int value;};

struct Num2 : Num { Num2(int v = 0) : Num(v) { } void add(int a) { value += a; }};

void f(Num& n) { cout << n.value << endl; }

int main(int, char**) { Num x(5); Num2 y(5); f(x); f(y); return 0;}

Polymorhism: Inclusion (Subtyping)Polymorhism: Inclusion (Subtyping)

Page 5: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

5

struct Num { Num(int v = 0) : value(v) { } int value;};

struct Person { Person(const char* name) : value(name) { } const char* value;};

template<typename T>void f(T& t) { cout << t.value << endl; }

int main(int, char**) { Num x(5); Person y("Christopher Nolan"); f(x); f(y); return 0;}

Polymorphism: ParametricPolymorphism: Parametric

Page 6: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

6

Taxonomy of PolymorphismTaxonomy of Polymorphism Ad-hoc

Overloading Coercion

Universal Inclusion (subtyping) Parametric

Page 7: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

7

Parametric PolymorphismParametric Polymorphism

Allows definitions to be parametrized at compile-time Such a definition is actually a “function” that returns a

new program element(method, class, etc.)

Template parameters = The arguments of this “function” AKA: type parameters

Instantiation of a template == evaluating the “function”

Page 8: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

8

Template Instantiation in C++Template Instantiation in C++

The compiler recompiles the template definition Substitutes the formal template parameters with the

actual parameters Generates new object code

Almost no compilation when the definition is read Most compilation work is at each instantiation point

The template definition must be part of the source code That is: #included from an .h file Supporting separate compilation of templates is too

difficult in practice

Page 9: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

9

C++ Function TemplatesC++ Function Templates A function can have type parameters

template<typename T> T* create() { return new T(); } void f() { string* sp = create<string>(); }

we use create() thru explicit instantiation We specify the actual types inside a pair of < >

In some cases the compiler can deduce the template parameterstemplate<typename T> void print(T& t) { cout << t << endl; }void g() { print(5); }

We use print() thru implicit instantiation Possible if a type parameter is also a value parameter Make overload resolution more difficult Introduced later

Page 10: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

10

A Template Taking a ConstantA Template Taking a Constanttemplate<int N>struct FixedArray { double values[N]; int size() { return N; } // Could be static};

int main(int, char**) { FixedArray<10> arr; arr.values[0] = 3.14; cout << "first element=" << arr.values[0] << endl; cout << "size=" << arr.size() << endl; return 0;}

Page 11: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

11

A Template Taking a Function Pointer A Template Taking a Function Pointer template<void (*F)()>struct Caller { static void run() { F(); }};

void hi() { cout << "hi" << endl;}void bye() { cout << "bye" << endl; } int main(int, char**) { Caller<hi>::run(); Caller<bye>::run(); return 0;}

Page 12: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

12

A Template Taking a TypeA Template Taking a Typetemplate<typename T>struct Pair { void set(const T& x, const T& y) { a = x; b = y; } void print() { cout << a << "," << b << endl; } private: T a, b; };

typedef Pair<char*> StrPair; // Instantiate Pair, // pass char* as an argument

typedef Pair<int> IntPair; int main(int, char**) { StrPair sp; IntPair ip; sp.set("ab", "cd"); sp.print(); ip.set(10, 20); ip.print(); return 0;}

Page 13: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

13

SpecializationSpecializationtemplate<typename T>struct Pair { void set(const T& x, const T& y) { a = x; b = y; } void print() { cout << a << "," << b << endl; } private: T a, b; };

template<>struct Pair<bool> { void set(bool x, bool y) { v = (x?1:0) + (y?2:0); } void print() { cout << (v&1) << "," << (v&2) << endl; } private: int v;}; int main(int, char**) { Pair<bool> pb; pb.set(true, false); pb.print(); Pair<char> pc; pc.set('x', 'y'); pc.print(); return 0;}

Page 14: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

14

A Non Conforming Specialization is LegalA Non Conforming Specialization is Legaltemplate<typename T>struct Pair { void set(const T& x, const T& y) { a = x; b = y; } void print() { cout << a << "," << b << endl; } private: T a, b; };

template<>struct Pair<bool> { void set(bool x, bool y) { v = (x?1:0) + (y?2:0); } public: int v;}; void doSomething() { Pair<bool> pb; pb.set(true, false); cout << pb.v << endl; Pair<char> pc; pc.set('x', 'y'); pc.print(); pb.print(); // Error. Pair<bool>::print() is undefined}

Page 15: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

15

C++ Templates: Interim SummaryC++ Templates: Interim Summary A template is a “function”

Arguments: types, constants Return value : A new class or a new function

Recognized by the compiler

The template is recompiled with each Instantiation

Specialization == “if” Different result based on the actual arguments

Page 16: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

16

C++ Templates as a C++ Templates as a Programming LanguagesProgramming Languages

Values?

Fundamental computational step?

What is the run-time phase?

What is the compile-time phase?

Type system: static or dynamic?

How powerful is it? What programs can we write in this language?

We saw that we can do “if” decisions

What sorts of bugs does it have? Can we run into an infinite loop?

Page 17: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

17

A Non-Terminating CompilationA Non-Terminating Compilationtemplate<typename T>struct Loop{ typedef typename Loop<Loop<T> >::Temp Temp;};

int main(int, char**) { Loop<int> n; return 0;}

Page 18: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

18

ConceptsConcepts Concept = A set of requirements that a type (or a set of

types) should uphold Requirements == constraints == expectations A generalization of structural conformance

A C++ template defines a concept Expects its type parameter to support certain operations

But the concept is implict The requirements are not clearly defined They are hidden inside the code

Page 19: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

19

Modelling the “From” ConceptModelling the “From” Concept

template<typename From, typename To>void copy(From& f, To& t) { for(int x = f.get(); !f.eof(); x = f.get()) t.put(x); }

struct Range { char begin, end; Range(char b, char e) : begin(b), end(e) { } int get() { return eof() ? -1 : begin++; } bool eof() { return begin > end; }};

int main(int, char**) { Range r('a', 'z'); copy(r, cout); return 0;}

Page 20: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

20

Same Program w/ InheritanceSame Program w/ Inheritancevoid copy(istream& f, ostream& t) { for(int x = f.get(); !f.eof(); x = f.get()) t.put(x);}

struct Range : istream { // Does istream have virtual methods?

// If it does, which one of these should be overridden

// int istream::peek() ?

// int istream::get()

// istream& istream::ignore(streamsize num, int delim) ?

// istream& istream::get(char& c)

// istream& istream::putback(char c)

// istream& istream::unget(char c)

// istream& istream::get(char* buf)

// istream& istream::getline(char* buf, streamsize num)

// istream& istream::read(char* buf, streamsize num)

// streamsize istream::gcount()

// pos_type istream::tellg()

// ... }

Page 21: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

21

Cryptic Error Messages Cryptic Error Messages struct Num { // The problem: Copy c'tor is not public public: Num() { } private: Num(const Num& other) { } };

template<typename T> void f() { vector<vector<T> > matrix; matrix.push_back(vector<T>()); }

template<typename V,typename T>void g() { (new V())->push_back(T()); }

template<typename V,typename T>void hh() { g<V,T>(); f<T>(); }

template<typename T>void h() { hh<vector<Num>,T>(); }

int main(int, char**) { h<Num>(); return 0; }

Page 22: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

22

Cryptic Error Messages (Cont.)Cryptic Error Messages (Cont.)x.cpp: In function ‘void std::_Construct(_T1*, const _T2&) [with _T1 = Num, _T2 = Num]’:

/usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/stl_uninitialized.h:86: instantiated from ‘_ForwardIterator std::__uninitialized_copy_aux(_InputIterator, _InputIterator, _ForwardIterator, __false_type) [with _InputIterator = __gnu_cxx::__normal_iterator<const Num*, std::vector<Num, std::allocator<Num> > >, _ForwardIterator = Num*]’

/usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/stl_uninitialized.h:113: instantiated from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const Num*, std::vector<Num, std::allocator<Num> > >, _ForwardIterator = Num*]’

/usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/stl_uninitialized.h:254: instantiated from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>) [with _InputIterator = __gnu_cxx::__normal_iterator<const Num*, std::vector<Num, std::allocator<Num> > >, _ForwardIterator = Num*, _Tp = Num]’

/usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/stl_vector.h:234: instantiated from ‘std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = Num, _Alloc = std::allocator<Num>]’

x.cpp:15: instantiated from ‘void f() [with T = Num]’

x.cpp:22: instantiated from ‘void hh() [with V = std::vector<Num, std::allocator<Num> >, T = Num]’

x.cpp:25: instantiated from ‘void h() [with T = Num]’

x.cpp:27: instantiated from here

x.cpp:9: error: ‘Num::Num(const Num&)’ is private

/usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/stl_construct.h:81: error: within this context

x.cpp: In function ‘void std::_Construct(_T1*, const _T2&) [with _T1 = Num, _T2 = Num]’:

/usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/stl_uninitialized.h:86: instantiated from ‘_ForwardIterator std::__uninitialized_copy_aux(_InputIterator, _InputIterator, _ForwardIterator, __false_type) [with _InputIterator = __gnu_cxx::__normal_iterator<const Num*, std::vector<Num, std::allocator<Num> > >, _ForwardIterator = Num*]’

...

Page 23: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

23

Documenting ConceptsDocumenting Concepts Understanding the type requirements from error messages

is very difficult

The solution: documentation

Here are two examples from SGI's STL web-site http://www.sgi.com/tech/stl/Assignable.html http://www.sgi.com/tech/stl/UnaryFunction.html

Page 24: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

24

Concept: AssignableConcept: Assignable

Refinement of-

Modelsint

NotationX A type that is a model of Assignablex,y Object of type X

Valid expressionsName Syntax Return-type Post-condition=======================================================Copy-ctor X(x) X X(x) is a copy of xAssignment x = y X& x is a copy ySwap swap(x,y) void Same as: X t = x; x = y; y = t

Page 25: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

25

Concept: Unary FunctionConcept: Unary FunctionRefinement of

Assignable

Modelschar (*)(int)

NotationF A type that is a model of Unary FunctionX The argument type of FResult The result type of Ff Object of type Fx Object of type X

Valid expressionsName Syntax Return-type Post-condition=======================================================call f(x) Result Return value is in f's range

Page 26: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

26

Concept: PrintableConcept: PrintableRefinement of

Assignable

Models???

NotationP,Q A type that is a model of Printablep,q Object of type P, Q (respectively)

Valid expressionsName Syntax Return-type Post-condition=======================================================ctor P p(q) P p has a copy of qprint p.print() void print() sent to p's copy of q

Page 27: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

27

Can we Model the Printable Concept?Can we Model the Printable Concept?

class Printable { ??? };

struct X { print() { ... } };struct Y { print() { ... } };struct Z { };

vector<Printable> vec;vec.push_back(X()); // OK -- X defines print() vec.push_back(Y()); // OK -- Y defines print() Printable& p = vec[0]; // p references the copy of x inside the vectorp.print(); // invoke print() on that copy of xp = vec[1]; // p references the copy of y inside the vector

vec.push_back(Z()); // Error -- Z does not defines print() Printable q = Z(); // Error -- Z does not defines print()

Page 28: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

28

Printable: the void* ApproachPrintable: the void* Approachstruct Printable void* data;

template<typename T> Printable(const T& t) { t.print(); // Ugly data = new T(t); }

virtual ~Printable() { delete data; } // Cannot delete a void pointer

Printable(const Printable& p) { data = new ??? p.data; } // Which type to create?

void print() { data -> ??? } // Cannot send print() to void* // Cannot downcast - there's no common superclass};

Page 29: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

29Printable: the Right WayPrintable: the Right Waystruct Base { virtual ~Base() { } virtual Base* clone() const = 0; virtual void print() = 0;};

template<typename U>struct Holder : Base { U* u; Holder(const U& arg) : u(new U(arg)) { } ~Holder() { delete u; } Base* clone() const { return new Holder(*u); } void print() { u->print(); }};

struct Printable { Base* holder;

template<typename T> Printable(const T& t) : holder(new Holder<T>(t)) { }

Printable(const Printable& p) : holder(p.holder->clone()) { }

virtual ~Printable() { delete holder; } void print() { holder->print(); }};

Page 30: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

30

Printable: The Assignment OperatorPrintable: The Assignment Operator

struct Printable {

Base* holder; ...

void swap(Printable& p) { Base* temp = holder; holder = p.holder; p.holder = temp; }

Printable& operator=(const Printable& p) { Printable temp(p); swap(temp); return *this; }};

Page 31: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

31Is This a Good Alternative? No!Is This a Good Alternative? No!

struct Printable {

Base* holder; ...

Printable& operator=(const Printable& p) { if(this == &p) return *this; delete holder; holder = p.holder.clone(); return *this; }};

Page 32: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

32

C++ Templates: Main PointsC++ Templates: Main Points

A functional programming language

Turing complete Has the same power as any other programming

language

Runs while the compiler compiles We build a tree (of types) at compile-time When an error occurs the compiler prints the path from

the root of this tree

Page 33: 1 Parametric Polymorphism  Polymorphism Techniques  C++ Templates

33

C++ Polymorphism: C++ Polymorphism: Templates vs. InheritanceTemplates vs. Inheritance

Templates - pros: Type safety - as in collections

Parametrize the protocol of a class Easier to define a compatible type

Require only structural conformance A type parameter can serve as a super class

Mixin Faster

Inheritance – pros: Polymorphism happens at run-time

E.g.: type of object is determined by an input value Readable error messages No executable blow up Separate compilation (templates must be #included)