Download presentation
Presentation is loading. Please wait.
Published byShannon Terry Modified over 8 years ago
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
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.