template

Concepts and Models
• Templates impose requirements on type parameters
– Types that are plugged in must meet those requirements
– Otherwise, the code won’t compile (and errors will say why)
• The set of requirements imposed is called a concept
• Any specific type that meets the requirements is a
model of that concept
• What requirement(s) does the expression
return first; impose?
Iterator
• What about
while(first != last && *first != value) {
++first;
}
const T &
CSE 332: C++ template examples
Interface Polymorphism: Concept Refinement
• A concept C is a refinement of
concept D if C imposes all of
the requirements of D
• Modeling and refinement
satisfy three formal properties
– Reflexivity: A concept refines
itself
– Containment: if T models C and
C refines D then T models D
– Transitivity: If C refines D then
C refines any concept D refines
• What in the OO paradigm is
this like? How does it differ?
C0
transitivity
C1
T1
T2
containment
T3
C2
T4
can substitute, e.g., T3 for T1
CSE 332: C++ template examples
One Last Detail: Associated Types
template <typename T>
class Array :
public ArrayBase {
public:
typedef T* iterator;
Array(const int size);
~Array();
iterator begin () {
return m_values;}
iterator end () {
return m_values+m_size;}
private:
T * m_values;
};
• A type parameter is not
concrete until its instantiated
• The compiler can work
around that in many cases
• But sometimes the compiler
needs more information
• Additional information can be
associated with a type
void foo {
Array<int> a;
fill_array(a);
for (Array<int>::iterator i =
a.begin(); i != a.end(); ++i) {
cout << *i << “ ” << endl;
}
}
CSE 332: C++ template examples
– For example, a class template
can define an iterator type
– Available to the template and
code that uses the template
– More about how this is done
(and why) in later lectures
C++ Templates and Interface Polymorphism
• Two examples
– Function template for printing different types
– Class template for a linked list
• First example will refine a program several times
– Ending up with a specialized reusable function template
– Shows how to write general and specialized templates
• Second example will walk through finished code
– Look at how to declare and define a class template
– Look at another data structure that uses dynamic memory
– A few practicalities you may need to know about
• E.g., including template source, working around compiler issues
CSE 332: C++ template examples
First Example: Printing Different Types
#include <iostream>
using namespace std;
int main (int, char *[]) {
•
•
•
•
int i = 7;
bool b = false;
int * ip = &i;
char * cp = "hello, world!";
void * vp = cp;
cout
cout
cout
cout
cout
<<
<<
<<
<<
<<
"i is " << i << endl;
"b is " << b << endl;
"ip is " << ip << endl;
"cp is " << cp << endl;
"vp is " << vp << endl;
return 0;
}
Large number of types in C++
Each handled a bit differently
For example, << with ostream
Simply giving to cout gives
i is 7
b is 0
ip is 0xfef69094
cp is hello, world!
vp is 0x8048a3c
• Let’s make some improvements
CSE 332: C++ template examples
Improve the Output for bool
#include <iostream>
using namespace std;
int main (int, char *[]) {
. . .
• First, fix how bool is output
• Use an iostream manipulator
std::boolalpha
– prints true or false
– Instead of 1 or 0
cout << "i is " << i << endl;
cout << "b is " << boolalpha
<< b << endl;
cout << "ip is " << ip << endl;
cout << "cp is " << cp << endl;
cout << "vp is " << vp << endl;
• Now we get
return 0;
}
i is 7
b is false
ip is 0xfef2aa04
cp is hello, world!
vp is 0x8048b0c
• But what about the pointers?
CSE 332: C++ template examples
Improve the Output for Pointers
#include <iostream>
using namespace std;
int main (int, char *[]) {
. . .
cout << "i is " << i << endl;
• Now, fix pointers
• Use reinterpret_cast
– Convert char * to void *
cout << "b is " << boolalpha
<< b << endl;
• Use dereferencing
cout << "ip is " << ip <<
" (points to " << *ip
<< ")" << endl;
• Now we have what we want
– Convert int * to int
cout << "cp is " <<
reinterpret_cast<void *> (cp)
<< " (points to \"" << cp
<< "\")" << endl;
cout << "vp is " << vp <<
return 0;
}
i is 7
b is false
ip is 0xfef23584 (points to 7)
cp is 0x8048b70 (points to "hello, world!")
vp is 0x8048b70
• But, don’t want to have to do
all that over again
endl;
CSE 332: C++ template examples
– Next time we want to print
Refactor the Code with a Function Template
#include <iostream>
using namespace std;
#include "common_T.h"
template <typename T>
void print (ostream & os,
const char * message,
const T & t) {
os << message << t << endl;
}
int main (int, char *[]) {
int i = 7;
bool b = false;
int * ip = &i;
char * cp = "hello, world!";
void * vp = cp;
• Define print function template
print(cout,
print(cout,
print(cout,
print(cout,
print(cout,
return 0;
}
"i is ", i);
"b is ", b);
"ip is ", ip);
"cp is ", cp);
"vp is ", vp);
– Consistent interface across types
– Just pass message, variable
• With this template we get
i is 7
b is 0
ip is 0xfeea28f4
cp is hello, world!
vp is 0x8048adc
• Right back where we started?
CSE 332: C++ template examples
Template Specialization: More Polymorphism
typedef char * charptr;
typedef int * intptr;
template <> void print
(ostream & os, const char * message,
const bool & b) {
os << message << std::boolalpha
<< b << endl;
}
template <> void print
(ostream & os, const char * message,
const charptr & s) {
os << message
<< reinterpret_cast<void *> (s);
if (s != 0) {
os << " (points to \""
<< s << "\")"; }
os << endl;
}
template <> void print
(ostream & os, const char * message,
const intptr & ip) {
os << message << ip;
if (ip != 0) {
os << " (points to " << *ip << ")"; }
os << endl;
}
template <typename T>
void print (ostream & os,
const char * message,
const T & t) {
os << message << t << endl;
}
• Specialize on individual types
bool
char *
int *
– Notice the use of typedef
• With specialization, we get
i is 7
b is false
ip is 0xfeebf064 (points to 7)
cp is 0x8048c30 (points to "hello, world!")
vp is 0x8048c30
• And, we can reuse the solution!
CSE 332: C++ template examples
Concluding Remarks (1 of 2)
• The set of requirements that a class template or
function template places on its parameterized types is
called a concept in generic programming terminology
• Any type that meets those requirements is said to
model the concept, and can be used in that template
• Concept refinement supports interface polymorphism
• Push common code and variables up into nontemplate base classes
– Can help avoid subtle type errors
– Can help reduce the size of the executable program
• Associated types expand the power of templates
– E.g., used extensively in the C++ Standard Template Library
CSE 332: C++ template examples
Concluding Remarks (2 of 2)
• Summary of generic programming ideas
– Can use templates to plug different types into
function and class declarations/definitions
– Can look at template code to come up with what the
requirements are for its parameterized types
• Fortunately, someone has already done that for the STL
• See Matt Austern’s book (CSE 532) for more details
CSE 332: C++ template examples