TEMPLATES
Michael Heron
Introduction
• In a previous lecture we talked very briefly about the idea
of parametric polymorphism.
• Being able to treat specific types of object independent of what
they actually are.
• In this lecture we are going to talk about C++’s templating
system.
• This lets us incorporate parametric polymorphism correctly in our
programs.
The Problem
• Say we want to create a basic kind of data structure.
• A queue
• A stack
• A hashmap
• How do we do that and still be able to deal with object
orientation?
• Answer is not immediately straightforward.
Java, Pre 1.5
• Many kinds of standard data structures exist as the
standard libraries in Java.
• Such as ArrayLists.
• Before version 1.5, the following syntax was used.
• Requires explicit casting of objects as they come off of the structure.
• Why?
• Polymorphism
Arraylist list = new ArrayList();
String str;
list.add (“Bing”);
list.add (“Bong”);
str = (String)list.get(0);
Java, 1.5+
• New versions of Java work with a different, more
demonic syntax.
• Explicit type information recorded along with the structure.
• No need for casting as things come off of the structure.
• How is such a thing achieved??
Arraylist<String> list = new ArrayList<String>();
String str;
list.add (“Bing”);
list.add (“Bong”);
str = list.get(0);
Generics/Templates
• The system in Java and C# is known as the
generics system.
• In C++, it’s called Templating.
• Both systems are roughly equivalent.
• Used for the same purpose, with various technical
differences.
• Templates more powerful than the Java/C# implementation.
• Provides a method for type-casting structures to permit
more elegant syntactic representation.
• Permits compile time checking of homogenous
consistency.
How Do They Work?
• Code we provide serves as a template for C++ to
generate specific instances of the code.
• Works like a structure that can deal with data at a family level of
granularity.
• Exists in two kinds:
• Function templates
• Class templates
Function Templates
• Function templates mimic a more flexible form of
method overloading.
• Overloading requires a method to be implemented for
all possible types of data.
• Function templates allow us to resolve that down
to a single template definition.
• Compiler can analyse provided parameters to
assess the function that must be created.
• Within limits… cannot interpret functionality where it
isn’t syntactically valid.
Function Templates
template <class T>
T add_nums(T a, T b);
#include <iostream>
#include "TemplateTest.h"
using namespace std;
template <typename T>
T add_nums(T num1, T num2)
{
return num1+num2;
}
int main() {
cout << add_nums ('a', 1) << endl;
return 0;
}
Ambiguity
• Because it is the compiler doing the work of interpreting
parameters, it cannot deal well with ambiguity.
• Where we say T, we must have it apply consistently across a
function call.
• We can ensure a certain kind of template being called by
type-casting the function call.
Ambiguous Function Call
#include <iostream>
#include "TemplateTest.h"
using namespace std;
template <typename T>
T add_nums(T num1, T num2)
{
return num1+num2;
}
int main() {
cout << add_nums (2.0f, 1) << endl;
return 0;
}
Non-Ambiguous Function Call
#include <iostream>
#include "TemplateTest.h"
using namespace std;
template <typename T>
T add_nums(T num1, T num2)
{
return num1+num2;
}
int main() {
cout << add_nums<float> (2.0f, 1) << endl;
return 0;
}
Multi-Type Functions
#include <iostream>
#include "TemplateTest.h"
using namespace std;
template <typename T, typename S>
T add_nums(T num1, S num2)
{
return num1+num2;
}
int main() {
float f;
f = add_nums<float, int> (5.0f, 3);
cout << f << endl;
return 0;
}
Class Templates
• In a similar way, we can create templates for C++
classes that are type agnostic.
• Again, the compiler will infer typing from context where
it possibility can.
• Good design in C++ separates out definition and
implementation.
• Into .h and .cpp files.
• Slight problem with doing this the way we have
done previously.
• It won’t work.
Class Templates
• Templates are not real code.
• Not as we understand it.
• It’s like a template letter in a word processor.
• Until the details are filled in, it’s not an actual letter.
• When separating out the definitions, the compiler
can’t deal with the T until it knows what types it’s
working with.
• The code doesn’t exist until you use it.
• This causes linking problems in the compiler.
Class Template Problems
• The complete definition for a function must be available at
the point of use.
• If the full definition isn’t available, the compiler assumes it has been
defined elsewhere.
• In the main program, it knows the type of the data type we
want to use.
• In the definition file, it doesn’t.
• So it never generates the appropriate code.
• Solution – inline functions.
A Stack Template
template <typename T>
class Stack {
private:
T *stack;
int current_size;
public:
Stack() :
stack (new T[100]),
current_size (0) {
}
void push(T thing) {
if (current_size == 100) {
return;
}
stack[current_size] = thing;
current_size += 1;
}
A Stack Template
T pop() {
T tmp;
current_size -= 1;
tmp = stack[current_size];
return tmp;
}
void clear() {
current_size = 0;
}
int query_size() {
return current_size;
}
~Stack() {
delete[] stack;
}
};
Using The Stack
#include <iostream>
#include <String>
#include "Stack.h"
using namespace std;
int main() {
Stack<int> *myStack;
myStack = new
Stack<int>();
myStack->push (100);
cout << myStack->pop()
<<
endl;
return 0;
}
#include <iostream>
#include <String>
#include "Stack.h"
using namespace std;
int main() {
Stack<string> *myStack;
myStack = new
Stack<string>();
myStack->push ("Hello");
cout << myStack->pop() <<
endl;
return 0;
}
Benefits of Templates
• Templates allow us to have classes and functions that
work independently of the data they use.
• No need to write a hundred different stacks, just write one using a
template.
• No significant performance overhead.
• It takes a little time for the compiler to generate the actionable
code, but it is not significant.
Qualified and Unqualified Names
• What does the typename keyword mean in C++?
• Have to go back quite a ways to explain this!
• Remember in our first header files, we’d often tell
them to use a namspace?
• To get access to the string class for one example.
• This is not good practice.
• We tell every class that uses the header to make use of
that namespace.
Qualified Names
• Qualified names are those that specifically note a
scope in a reference.
• For example, string is defined in std, thus:
• std::string
• std::cout
• Scope is independent of using a namespace
#include <iostream>
int main() {
std::cout << "Bing!" << std::endl;
return 0;
}
The Problem
template<class S>
void do_something()
{
S::x1 * x2;
}
What are we doing here?
Accessing a member variable called X1 in the parametrized class S?
Or…
Creating a pointer of type S::x1, with the name x2?
Typename resolves this problem.
One Last Thing…
• It’s often important to handle deep copies in templates.
• For the same reason it’s important in normal classes.
• Must include copy constructors and assignment operators
here.
• Remember the rules regarding these with reference to pointers and
others.
Deep Copies on Templates
Stack<T>(const Stack<T> &s) {
current_size = s.current_size;
stack = new T[100];
for (int i = 0; i < 100; i++) {
stack[i] = s.stack[i];
}
}
Remember these are designed to work on value objects and must be explicitly
de-referenced when working with pointers, like so:
Stack<string> *myStack, *stack2;
myStack = new Stack<string>;
stack2 = new Stack<string>(*myStack);
Deep Copies on Templates
Stack<T>& operator= (const Stack<T> &s) {
current_size = s.current_size;
delete[] stack;
stack = new T[100];
for (int i = 0; i < 100; i++) {
stack[i] = s.stack[i];
}
return (*this);
}
Summary
• Method overloading offers a degree of ad hoc
polymorphism.
• Combinations must be specified initially.
• Templates permit for parametric polymorphism.
• More complex, but a powerful way of creating generic data types.
• We’ll see the power of this in the next lecture.

2CPP15 - Templates

  • 1.
  • 2.
    Introduction • In aprevious lecture we talked very briefly about the idea of parametric polymorphism. • Being able to treat specific types of object independent of what they actually are. • In this lecture we are going to talk about C++’s templating system. • This lets us incorporate parametric polymorphism correctly in our programs.
  • 3.
    The Problem • Saywe want to create a basic kind of data structure. • A queue • A stack • A hashmap • How do we do that and still be able to deal with object orientation? • Answer is not immediately straightforward.
  • 4.
    Java, Pre 1.5 •Many kinds of standard data structures exist as the standard libraries in Java. • Such as ArrayLists. • Before version 1.5, the following syntax was used. • Requires explicit casting of objects as they come off of the structure. • Why? • Polymorphism Arraylist list = new ArrayList(); String str; list.add (“Bing”); list.add (“Bong”); str = (String)list.get(0);
  • 5.
    Java, 1.5+ • Newversions of Java work with a different, more demonic syntax. • Explicit type information recorded along with the structure. • No need for casting as things come off of the structure. • How is such a thing achieved?? Arraylist<String> list = new ArrayList<String>(); String str; list.add (“Bing”); list.add (“Bong”); str = list.get(0);
  • 6.
    Generics/Templates • The systemin Java and C# is known as the generics system. • In C++, it’s called Templating. • Both systems are roughly equivalent. • Used for the same purpose, with various technical differences. • Templates more powerful than the Java/C# implementation. • Provides a method for type-casting structures to permit more elegant syntactic representation. • Permits compile time checking of homogenous consistency.
  • 7.
    How Do TheyWork? • Code we provide serves as a template for C++ to generate specific instances of the code. • Works like a structure that can deal with data at a family level of granularity. • Exists in two kinds: • Function templates • Class templates
  • 8.
    Function Templates • Functiontemplates mimic a more flexible form of method overloading. • Overloading requires a method to be implemented for all possible types of data. • Function templates allow us to resolve that down to a single template definition. • Compiler can analyse provided parameters to assess the function that must be created. • Within limits… cannot interpret functionality where it isn’t syntactically valid.
  • 9.
    Function Templates template <classT> T add_nums(T a, T b); #include <iostream> #include "TemplateTest.h" using namespace std; template <typename T> T add_nums(T num1, T num2) { return num1+num2; } int main() { cout << add_nums ('a', 1) << endl; return 0; }
  • 10.
    Ambiguity • Because itis the compiler doing the work of interpreting parameters, it cannot deal well with ambiguity. • Where we say T, we must have it apply consistently across a function call. • We can ensure a certain kind of template being called by type-casting the function call.
  • 11.
    Ambiguous Function Call #include<iostream> #include "TemplateTest.h" using namespace std; template <typename T> T add_nums(T num1, T num2) { return num1+num2; } int main() { cout << add_nums (2.0f, 1) << endl; return 0; }
  • 12.
    Non-Ambiguous Function Call #include<iostream> #include "TemplateTest.h" using namespace std; template <typename T> T add_nums(T num1, T num2) { return num1+num2; } int main() { cout << add_nums<float> (2.0f, 1) << endl; return 0; }
  • 13.
    Multi-Type Functions #include <iostream> #include"TemplateTest.h" using namespace std; template <typename T, typename S> T add_nums(T num1, S num2) { return num1+num2; } int main() { float f; f = add_nums<float, int> (5.0f, 3); cout << f << endl; return 0; }
  • 14.
    Class Templates • Ina similar way, we can create templates for C++ classes that are type agnostic. • Again, the compiler will infer typing from context where it possibility can. • Good design in C++ separates out definition and implementation. • Into .h and .cpp files. • Slight problem with doing this the way we have done previously. • It won’t work.
  • 15.
    Class Templates • Templatesare not real code. • Not as we understand it. • It’s like a template letter in a word processor. • Until the details are filled in, it’s not an actual letter. • When separating out the definitions, the compiler can’t deal with the T until it knows what types it’s working with. • The code doesn’t exist until you use it. • This causes linking problems in the compiler.
  • 16.
    Class Template Problems •The complete definition for a function must be available at the point of use. • If the full definition isn’t available, the compiler assumes it has been defined elsewhere. • In the main program, it knows the type of the data type we want to use. • In the definition file, it doesn’t. • So it never generates the appropriate code. • Solution – inline functions.
  • 17.
    A Stack Template template<typename T> class Stack { private: T *stack; int current_size; public: Stack() : stack (new T[100]), current_size (0) { } void push(T thing) { if (current_size == 100) { return; } stack[current_size] = thing; current_size += 1; }
  • 18.
    A Stack Template Tpop() { T tmp; current_size -= 1; tmp = stack[current_size]; return tmp; } void clear() { current_size = 0; } int query_size() { return current_size; } ~Stack() { delete[] stack; } };
  • 19.
    Using The Stack #include<iostream> #include <String> #include "Stack.h" using namespace std; int main() { Stack<int> *myStack; myStack = new Stack<int>(); myStack->push (100); cout << myStack->pop() << endl; return 0; } #include <iostream> #include <String> #include "Stack.h" using namespace std; int main() { Stack<string> *myStack; myStack = new Stack<string>(); myStack->push ("Hello"); cout << myStack->pop() << endl; return 0; }
  • 20.
    Benefits of Templates •Templates allow us to have classes and functions that work independently of the data they use. • No need to write a hundred different stacks, just write one using a template. • No significant performance overhead. • It takes a little time for the compiler to generate the actionable code, but it is not significant.
  • 21.
    Qualified and UnqualifiedNames • What does the typename keyword mean in C++? • Have to go back quite a ways to explain this! • Remember in our first header files, we’d often tell them to use a namspace? • To get access to the string class for one example. • This is not good practice. • We tell every class that uses the header to make use of that namespace.
  • 22.
    Qualified Names • Qualifiednames are those that specifically note a scope in a reference. • For example, string is defined in std, thus: • std::string • std::cout • Scope is independent of using a namespace #include <iostream> int main() { std::cout << "Bing!" << std::endl; return 0; }
  • 23.
    The Problem template<class S> voiddo_something() { S::x1 * x2; } What are we doing here? Accessing a member variable called X1 in the parametrized class S? Or… Creating a pointer of type S::x1, with the name x2? Typename resolves this problem.
  • 24.
    One Last Thing… •It’s often important to handle deep copies in templates. • For the same reason it’s important in normal classes. • Must include copy constructors and assignment operators here. • Remember the rules regarding these with reference to pointers and others.
  • 25.
    Deep Copies onTemplates Stack<T>(const Stack<T> &s) { current_size = s.current_size; stack = new T[100]; for (int i = 0; i < 100; i++) { stack[i] = s.stack[i]; } } Remember these are designed to work on value objects and must be explicitly de-referenced when working with pointers, like so: Stack<string> *myStack, *stack2; myStack = new Stack<string>; stack2 = new Stack<string>(*myStack);
  • 26.
    Deep Copies onTemplates Stack<T>& operator= (const Stack<T> &s) { current_size = s.current_size; delete[] stack; stack = new T[100]; for (int i = 0; i < 100; i++) { stack[i] = s.stack[i]; } return (*this); }
  • 27.
    Summary • Method overloadingoffers a degree of ad hoc polymorphism. • Combinations must be specified initially. • Templates permit for parametric polymorphism. • More complex, but a powerful way of creating generic data types. • We’ll see the power of this in the next lecture.