C++ Training Datascope Lawrence D’Antonio - PowerPoint PPT Presentation

c training datascope lawrence d antonio n.
Download
Skip this Video
Loading SlideShow in 5 Seconds..
C++ Training Datascope Lawrence D’Antonio PowerPoint Presentation
Download Presentation
C++ Training Datascope Lawrence D’Antonio

play fullscreen
1 / 137
C++ Training Datascope Lawrence D’Antonio
131 Views
Download Presentation
daphne
Download Presentation

C++ Training Datascope Lawrence D’Antonio

- - - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript

  1. C++ TrainingDatascopeLawrence D’Antonio Lecture 7 An Overview of C++: What is Polymorphism? – Parametric Polymorphism

  2. What is polymorphism? Parametric Universal Subtype Polymorphism Overloading Ad-hoc Coercion Different types of objects respond to the same message and use the appropriate method.

  3. Parametric Polymorphism • Parametric polymorphism parametrizes the object type (e.g., a list class, where the type of object stored is parametrized). • Parametric polymorphism in C++ is implemented as templates. • Both classes and functions may be templates.

  4. Template Functions template<class T> T max(T a, T b) { return a > b ? a : b; }

  5. Is this legal? int a,b = 6; const int c = 3; double x,y = 3.2; a = max(b,4); a = max(b,c); x = max(y,3.3); x = max(b,y);

  6. a = max(b,4); //Legal, max<int,int> a = max(b,c); //Legal, max<int,int> x = max(y,3.3); //Legal, max<double,double> x = max(b,y); //Illegal, no max<int,double> A template function is called only when there is an exact match for type parameters (only trivial conversions, such as const int to int are allowed). But the following is legal. x = max<double>(4,4.2);

  7. Better max? template<class S, class T> T max(S a, T b) { return a > b ? a : b; } main() { int a, b = 3; double x, y = 3.2; a = max(b,5); x = max(y,5.4); x = max(b,y); x = max(y,b); return 0; }

  8. a = max(b,5); //Legal, returns 5 x = max(y,5.4); //Legal, returns 5.4 x = max(b,y); //Legal, 3.2 x = max(y,b); //Legal, but //returns 3.0!

  9. Best max? template<class R, class S, class T> R max(S a, T b) { return a > b ? a : b; } main() { int a, b = 3; double x, y = 3.2; a = max(b,5); x = max(y,5.4); x = max(b,y); x = max(y,b); return 0; }

  10. Doesn’t compile. The function max() is supposed to have 3 template parameters. But each call only uses 2 parameters.

  11. Try this max template<class R, class S, class T> R max(S a, T b) { return a > b ? a : b; } main() { int a, b = 3; double x, y = 3.2; a = max<int>(b,5); x = max<double>(y,5.4); x = max<double>(b,y); x = max<double>(y,b); return 0; }

  12. Is this legal? • Return back to the original definition of max. int x = 5, y = 6; int *p = &x, *q = &y; int z = max(p,q);

  13. Legal, but probably not what you want. max(p,q) compares addresses, not data values.

  14. Can we fix this? template<class T> T max(T a, T b) { return a > b ? a : b; } template<class T> T* max<T *a, T *b> { return *a > *b ? a : b; }

  15. Should we fix this? • Probably not. Overloading the max function to compare dereferenced pointers means that we can’t compare addresses using max.

  16. STL version of max template<class T> const T &max(const T &a, const T &b) { return a < b ? b : a; }

  17. Another problem const char *s = “Hello”; const char *t = “World”; std::string s = max(s,t); std::cout << s; What does this print out? Who knows? max returns the char* with the larger memory address.

  18. A Solution • Overload the max function. The second is called a template specialization. template<class T> const T& max(const T&a, const T&b) { return a < b ? b : a; } const char* max(const char *a,const char* b) { return std::strcmp(a,b) < 0 ? b : a; }

  19. STL Solution template<class T> const T& max(const T&a, const T&b) { return a < b ? b : a; } template<class T, class BinPred> const T& max(const T&a, const T&b, BinPred comp) { return comp(a,b) ? b : a; }

  20. Using a predicate bool comp(const char *a, const char *b) { return std::strcmp(a,b) < 0; } const char *s = “Hello”; const char *t = “World”; std::string s = max(s,t,comp);

  21. Functor solution class Comp { public: bool operator()(const char *a, const char *b) { return std::strcmp(a,b) < 0; } }; const char *s = “Hello”; const char *t = “World”; std::string s = max(s,t,Comp());

  22. Is this legal? std::string s1(“apple”); std::string s2(“tomato”); std::max(“apple”,”peach”); std::max(“apple”,”tomato”); std::max(“apple”,s1); std::max(s1,s2);

  23. std::max(“apple”,”peach”); //Legal, both arguments are const char[5] std::max(“apple”,”tomato”); //Illegal, arguments are different types std::max(“apple”,s1); //Illegal, arguments are different types std::max(s1,s2); //Legal, both arguments are type string

  24. Is this legal? template<class T> T foo() { return T(); } template<class T> void bar() { T t; } main() { int x = foo(); bar(); return 0; }

  25. Not legal for two reasons. int x = foo(); Illegal because the compiler doesn’t know which version of foo() to call. It won’t determine that foo() should return an int by looking at the LHS. bar(); Illegal because the compiler doesn’t know which version of bar() to call.

  26. Legal version of example template<class T> T foo() { return T(); } template<class T> void bar() { T t; } main() { int x = foo<int>(); bar<int>(); return 0; }

  27. Template name lookup • Template name resolution involves what is known as “two-phase name lookup”. • Template names are divided into two categories: dependent and non-dependent names. • Dependent and non-dependent names are resolved at different times.

  28. Dependent names • Dependent names have definitions that depend on template parameters, but have no declaration within the template definition. • Dependent names are only resolved at the time of instantiation.

  29. Non-dependent names • Non-dependent names are names that don’t depend on a template parameter, the name of the template itself, and names declared within it (members, friends, and local variables).

  30. Example template<class T> class X { T t; public: X(const T &a):t(a) { t.init(); } template<class U> T foo() { U u = t.begin(); return *u; } };

  31. Name resolution in example • Non-dependent names X, t, a, X(const T &), foo(), U, u • Dependent names T::init(), T::begin()

  32. SFINAE • “Substitution failure is not an error.” • When examining which template function to call from a set of overloaded template functions, there is no error if some substitutions are illegal.

  33. Example template<class Func, class T> void apply(Func f, T x) { f(x); } template <class T> void multi(T) { } template <class T*> void multi(T *) { } main() { apply(multi<int>,5); return 0; }

  34. apply(multi<int>,5) calls multi(T) with int substituting for T. The failure of the substitution of int in multi(T*) does cause an error.

  35. Is this legal? template<int N> int g() { return N; } template<int *P> int g() { return *P; } main() { return g<1>(); }

  36. Yes, this is legal (if odd looking). g<1> binds to g<int>, the failure to bind to g<int *> is not an error.

  37. Is this legal? template <class Alloc> class container_helper { typedef Alloc::value_type value_type; };

  38. Not legal, the compiler has no idea what the dependent name Alloc::value_type represents. Here is the correct version. template <class Alloc> class container_helper { typedef typename Alloc::value_type value_type; };

  39. Is this legal? template <class Alloc> class container_helper { typedef typename Alloc::value_type value_type; typedef std::pair<value_type,value_type> element_type; };

  40. Yes, this is legal. typedef std::pair<value_type,value_type> element_type; This can be resolved in scope.

  41. Is this legal? template <class Alloc> class container_helper { typedef typename Alloc::value_type value_type; typedef std::pair<value_type,value_type> element_type; typedef typename Alloc::rebind<element_type>::other element_allocator; };

  42. Not legal, perhaps surprisingly. The compiler cannot determine from Alloc::rebind<element_type>::other what rebind refers to (is it an object, a function, or Superman?).

  43. ADL • Argument-dependent lookup applies to unqualified names where it appears that a nonmember function is being called. • ADL proceeds by looking up a name in namespaces and classes associated with the types of the function call arguments.

  44. Which functions are called? #include <iostream> namespace X { template <class T> void f(T) { std::cout << "f<T>\n"; } } namespace N { using namespace X; enum E{ e1 }; void f(E) { std::cout << "f(E)\n"; } } void f(int) { std::cout << "f(int)\n"; } main() { ::f(N::e1); f(N::e1); return 0; }

  45. ::f(N::e1); //Qualified name, so calls global f, no ADL used f(N::e1); //Calls N::f. The call argument N::e1 is associated //with namespace N. So this means that N::f is //preferred over ::f. Note that X::f is not considered, //because using directives are ignored in ADL.

  46. Is this legal? template<typename T, typename Alloc = std::allocator<T> > class my_container : private container_helper<Alloc>::element_allocator { //... };

  47. Perhaps surprisingly this is legal. The dependent name container_helper<Alloc>::element_allocator cannot be resolved,. But since it is being used as a base class, the compiler is happy.

  48. What is rebind? • A template typedef. template <class T> class allocator { . . . template <class U> struct rebind { typedef allocator<U> other; }; ... template <class U> allocator(const allocator<U>&); };

  49. Use of rebind template <class T, class Allocator = allocator<T> > class list { private: typedef . . . listnode; typedef typename Allocator::rebind<listnode>::other Node_allocator; Node_allocator alloc_; list_node* make_node() { return new(alloc_.allocate(1)) list_node; } public: list(const Allocator& a = Allocator()) : alloc_(a) { } // implicit conversion . . . };

  50. Template classes • The declaration and definition of a template class “must” be in the same header file.