Presentation is loading. Please wait.

Presentation is loading. Please wait.

CNS 3370.  Template Specialization  Member Templates  Template Metaprogramming  Template Idioms  Templates and Friends 2 CNS 3370 - Templates.

Similar presentations


Presentation on theme: "CNS 3370.  Template Specialization  Member Templates  Template Metaprogramming  Template Idioms  Templates and Friends 2 CNS 3370 - Templates."— Presentation transcript:

1 CNS 3370

2  Template Specialization  Member Templates  Template Metaprogramming  Template Idioms  Templates and Friends 2 CNS 3370 - Templates

3  A template by nature is a generalization  It becomes specialized for a particular use when the actual template arguments are provided  A particular instantiation is therefore a specialization  But there is another type of “specialization”… 3 CNS 3370 - Templates

4  You may need special “one-off” behavior for certain template arguments  Common case: T = char*  You can provide custom code for each case  both full or partial specializations for class templates  the compiler will use your explicit versions instead of generating code from the primary template 4 CNS 3370 - Templates

5  Allowed, but not needed because you can always just provide a plain overloaded function to do the job  Exception: useful for when you only want to specialize a subset of the member functions of a class 5 CNS 3370 - Templates

6 // A Primary Template template class Foo { public: void f(); void g(); }; template void Foo ::f() { cout << "f using primary template\n"; } template void Foo ::g() { cout << "g using primary template\n"; } 6 CNS 3370 - Templates

7 // The Full Specialization template<> class Foo { public: void f(); void g(); }; // NOTE: No template keyword here // Also: These go in a.cpp void Foo ::f() { cout << "f using int specialization\n"; } void Foo ::g() { cout << "g using int specialization\n"; } 7 CNS 3370 - Templates

8 int main() { Foo c; Foo i; c.f(); c.g(); i.f(); i.g(); } /* Output: f using primary template g using primary template f using int specialization g using int specialization */ 8 CNS 3370 - Templates

9  You may specialize only selected member functions, if desired  The other member functions will come from the primary template  All types of members can be selectively specialized  Static members, Member templates 9 CNS 3370 - Templates

10 template<> void Foo ::g() { cout << "g using int specialization\n"; } int main() { Foo c; Foo i; c.f(); c.g(); i.f(); i.g(); } /* Output f using primary template g using primary template f using primary template g using int specialization */ 10 CNS 3370 - Templates

11  Can specialize on a subset of template arguments  Can also specialize on “pointer-ness” or “const- ness” of arguments  vector is actually a partial specialization:  It leaves the allocator type “open”: template class vector {…}; 11 CNS 3370 - Templates

12 template class C { public: void f() { cout << "Primary Template\n"; } }; template class C { public: void f() { cout << "T == int\n"; } }; template class C { public: void f() { cout << "U == double\n"; } }; template class C { public: void f() { cout << "T* used\n"; } }; template class C { public: void f() { cout << "U* used\n"; } }; 12 CNS 3370 - Templates

13 template class C { public: void f() { cout << "T* and U* used\n"; } }; template class C { public: void f() { cout << "T == U\n"; } }; int main() { C ().f(); // 1: Primary template C ().f(); // 2: T == int C ().f(); // 3: U == double C ().f(); // 4: T == U C ().f(); // 5: T* used [T is float] C ().f(); // 6: U* used [U is float] C ().f(); // 7: T* and U* used [float, int] // The following are ambiguous: // 8: C ().f(); // 9: C ().f(); // 10: C ().f(); // 11: C ().f(); // 12: C ().f(); } 13 CNS 3370 - Templates

14  You must provide all functions you want clients to have when specializing a class  An alternative is to only specialize selected member functions, leaving the rest to the primary template  You can do full or partial specializations of class templates  You can’t partially specialize function templates  And you shouldn’t fully specialize function templates ▪ Except as described above for member functions 14 CNS 3370 - Templates

15 15  Some things cannot be resolved when the compiler first encounters a template definition  Anything dependent on a template parameter  The compiler must wait until instantiation time to resolve those issues  When the actual template arguments are known  Hence, a 2-step template compilation process:  1) Template Definition  2) Template Instantiation

16 CNS 3370 - Templates 16  Template definition time  The template code is parsed  Obvious syntax errors are caught  Non-dependent names are looked up in the context of the template definition (no waiting needed)  Template instantiation time  Dependent names are resolved  Which specialization to use is determined  Examples follow…

17 CNS 3370 - Templates 17 void f(double) { cout << "f(double)" << endl; } template class X { public: void g() { f(1); } }; void f(int) { cout << "f(int)" << endl; } int main() { X ().g(); }

18  Non-dependent names are not looked up in base classes  Because a specialization found later may apply  If a class template has a dependent base class, you want calls looked up in Phase 2  When specializations are resolved  Calls to such functions must be qualified  This makes the name dependent  Otherwise they’ll be looked up in Phase 1 and will fail  See next slide… 18 CNS 3370 - Templates

19 19 template class PQV : protected vector { Compare comp; public: PQV(Compare cmp = Compare()) : comp(cmp) { make_heap(begin(),end(), comp); } const T& top() const { return front(); } void push(const T& x) { push_back(x); push_heap(begin(), end(), comp); } void pop() { pop_heap(begin(), end(), comp); pop_back(); } };

20 CNS 3370 - Templates 20 template class PQV : protected vector { Compare comp; public: PQV(Compare cmp = Compare()) : comp(cmp) { make_heap(this->begin(),this->end(), comp); } const T& top() const { return this->front(); } void push(const T& x) { this->push_back(x); push_heap(this->begin(),this->end(), comp); } void pop() { pop_heap(this->begin(),this->end(), comp); this->pop_back(); } };

21 CNS 3370 - Templates 21  When necessary, clue the compiler as to which names are dependent by qualifying them  They’ll get looked up in Phase 2  Remember:  Non-dependent names are looked up immediately  But not in dependent base classes ▪ “x” is not always the same as “this->x”!

22  Variables  Data members; either static or non-static  Functions  Member functions, either static and non-static  Types  Either nested classes or typedefs  Templates  “Member Templates”  Use independent template parameters 22 CNS 3370 - Templates

23 template class vector { public: class MyIteratorType {…}; typedef MyIteratorType iterator; … }; Can say: vector ::iterator p = v.begin(); 23 CNS 3370 - Templates

24  Can use typename instead of class in a template parameter declaration  Some people use class when the expected argument(s) must not be built-in types  And they use typename when “anything goes”  Just a style issue 24 CNS 3370 - Templates

25  Consider the expression T::X  When inside a template with type parameter T  The compiler assumes X refers to a static member (the parser has to assume something, since T is unknown at first)  Note: X is a dependent name  If X is a type, instead, use the typename keyword to inform the compiler… 25 CNS 3370 - Templates

26 // A Print function for standard sequences template > class Seq> void printSeq(Seq & seq) { for(typename Seq ::iterator b = seq.begin(); b != seq.end();) cout << *b++ << endl; } int main() { // Process a vector vector v; v.push_back(1); v.push_back(2); printSeq(v); // Process a list list lst; lst.push_back(3); lst.push_back(4); printSeq(lst); } 26 CNS 3370 - Templates

27  Infers the type of a variable from its initializer  very handy!!! for(auto b = seq.begin(); b != seq.end();) cout << *b++ << endl; CNS 3370 - Templates 27

28  Can also nest template definitions inside a class  Very handy for conversion constructors:  template class complex { public: template complex(const complex &);  Inside of STL sequences: template deque(InputIterator first, InputIterator last, const Allocator& = Allocator());  Example on next slide

29 template class Outer { public: template class Inner { public: void f(); }; template template void Outer ::Inner ::f() { cout << "Outer == " << typeid(T).name() << endl; cout << "Inner == " << typeid(R).name() << endl; cout << "Full Inner == " << typeid(*this).name() << endl; } int main() { Outer ::Inner inner; inner.f(); }

30 Outer == int Inner == bool Full Inner == Outer ::Inner

31  Example: std::bitset::to_s tring  template basic_string to_string() const;  Because strings are themselves templates! ▪ char vs. wchar_t  So you must explicitly specialize a call to bitset::to_string( ) to indicate the return type  But compilers assume member functions are not templates!  You need to give the compiler a clue about the ‘<‘

32  There are contexts in which a ‘<‘ will be interpreted as a less-than operation, instead of the beginning of a template argument list  When using member function templates, for example  The template keyword tells the compiler to assume that a template is being used instead of a less-than operation  Example on next slide:  Converts a bitset to a string (but needs to know the char type)  bitset::to_string( ) needs a template context: string s = bs.to_string, // error allocator >();

33 template basic_string bitsetToString(const bitset & bs) { return bs.template to_string, allocator >(); } int main() { bitset bs; bs.set(1); bs.set(5); cout << bs << endl; // 0000100010 string s = bitsetToString (bs); cout << s << endl; // 0000100010 }

34  Compile-time Computation!  whoa!  Has been proven to be “Turing complete”  means that theoretically, you can do anything at compile time  in practice, it’s used for custom code generation, compile-time assertions, and numerical libraries  See next slide and Hanoi.cpp 34 CNS 3370 - Templates

35 template struct binary { enum {value = binary ::value << 1 | N%10}; }; // A (full) specialization to stop the recursion. template<> struct binary { enum {value = 0}; }; int main() { cout ::value << endl; // 5 cout ::value << endl; // 622 cout ::value << endl; // 231 } 35 CNS 3370 - Templates

36  Traits  A Curiously Recurring Template Pattern CNS 3370 - Templates 36

37  A way to store type-specific code for templates  “Compile-time polymorphism”  Use separate template specializations for each type  Examples:  std::numeric_limits 37 CNS 3370 - Templates

38 template class numeric_limits { public: static const bool is_specialized = false; static T min() throw(); // for float, etc. static T max() throw(); static const int digits = 0; static const int digits10 = 0; static const bool is_signed = false; static const bool is_integer = false; static const bool is_exact = false; static const int radix = 0; static T epsilon() throw();... 38 CNS 3370 - Templates

39  Can use a static data member that tracks the object count  Constructors increment  Destructors decrement 39 CNS 3370 - Templates

40 // This is C++ 101: class CountedClass { static int count; public: CountedClass() { ++count; } CountedClass(const CountedClass&) { ++count; } ~CountedClass() { --count; } static int getCount() { return count; } }; int CountedClass::count = 0; 40 CNS 3370 - Templates

41  The logic for counting objects is type- independent  It would be a shame to replicate that code for each class to be counted  The non-template solution for code sharing is usually inheritance  See next slide… 41 CNS 3370 - Templates

42 class Counted { static int count; public: Counted() { ++count; } Counted(const Counted&) { ++count; } ~Counted() { --count; } static int getCount() { return count; } }; int Counted::count = 0; // All derived classes share the same count! class CountedClass : public Counted {}; class CountedClass2 : public Counted {}; 42 CNS 3370 - Templates

43  We need a separate count for each class to be counted  So we need to inherit from a different class for each client class  Hence, we need to use both inheritance (OOP/dynamic polymorphism) and templates (compile-time polymorphism)  See next slide… 43 CNS 3370 - Templates

44 template class Counted { static int count; public: Counted() { ++count; } Counted(const Counted &) { ++count; } virtual ~Counted() { --count; } static int getCount() { return count; } }; template int Counted ::count = 0; // Curious class definitions!!! class CountedClass : public Counted {}; class CountedClass2 : public Counted {}; 44 CNS 3370 - Templates

45  A class, T, inherits from a template that specializes on T!  class T : public X {…};  Only valid if X is not dependent on the (non- static) implementation of T  i.e., during Phase 1 45 CNS 3370 - Templates

46  Inherit Singleton-ness  Uses Meyers’ static singleton object approach  Since nothing non-static is inherited, the size is known at template definition time  Protected constructor, destructor  Disables copy/assign  See next slide… 46 CNS 3370 - Templates

47 // Base class – encapsulates singleton-ness template class Singleton { Singleton(const Singleton&); Singleton& operator=(const Singleton&); protected: Singleton() {} virtual ~Singleton() {} public: static T& instance() { static T theInstance; // Meyers' Singleton return theInstance; } }; 47 CNS 3370 - Templates

48 // A sample class to be made into a Singleton class MyClass : public Singleton { int x; protected: friend class Singleton ; // to create it MyClass() { x = 0; } public: void setValue(int n) { x = n; } int getValue() const { return x; } }; int main() { MyClass& m = MyClass::instance(); cout << m.getValue() << endl; m.setValue(1); cout << m.getValue() << endl; } 48 CNS 3370 - Templates

49 49

50  How can we add a stream inserter?  ostream& operator &); template class Box { T t; public: Box(const T& theT) : t(theT) {} }; 50 CNS 3370 - Templates

51 template class Box { T value; public: Box(const T& t) { value = t; } friend ostream& operator &); }; template ostream& operator b) { return os << b.value; } 51 CNS 3370 - Templates

52  The inserter is not a template  Because it’s not a member function  But it uses a template parameter (T)!  What do we want?  Our operator<<( ) should be a template  And we want a distinct specialization for each T  But it can’t be a member template! ▪ That would introduce an independent template parm  Aargh! 52 CNS 3370 - Templates

53  There are special rules for friend function templates to class templates  Use angle brackets in the declaration of the friend  But the friend must have been previously declared  This also requires a forward declaration of Box  See Next Slide 53 CNS 3370 - Templates

54 // Forward declarations template class Box; template ostream& operator<<(ostream&, const Box &); template class Box { T value; public: Box(const T& t) { value = t; } friend ostream& operator (ostream&, const Box &); }; template ostream& operator & b) { return os << b.value; } 54 CNS 3370 - Templates

55  Define body of op<< in situ (i.e.,inside of Box)  Such an op<< is not a template!  No angle brackets are used  A new ordinary function is created for each specialization of Box!  See next slide 55 CNS 3370 - Templates

56 template class Box { T value; public: Box(const T& t) { value = t; } friend ostream& operator & b) { return os << b.value; } }; 56 CNS 3370 - Templates


Download ppt "CNS 3370.  Template Specialization  Member Templates  Template Metaprogramming  Template Idioms  Templates and Friends 2 CNS 3370 - Templates."

Similar presentations


Ads by Google