You are on page 1of 30

Templates

Templates
• Generic Functions
• Applying Generic Functions
• Generic Classes
Generic Functions
• Syntax:
template <class Ttype> ret-type func-
name(parameter list)
{
// body of function
}
// Function template example. swapargs(i, j); // swap integers
#include <iostream> swapargs(x, y); // swap floats
using namespace std; swapargs(a, b); // swap chars

// This is a function template.


cout <<“\nSwapped i, j: " << i << ' ' << j ;
template <class X> void swapargs(X &a,X &b)
cout <<“\nSwapped x, y: " << x << ' '<<y;
{
X temp; cout <<“\nSwapped a, b: " << a << ' ‘<<b;
temp = a; return 0;
a = b; }
b = temp;
}

int main()
{
int i=10, j=20;
double x=10.1, y=23.3;
char a='x', b='z';
cout <<“\nOriginal i, j: " << i << ' ' << j ;
cout <<“\nOriginal x, y: " << x << ' ' << y;
cout <<“\nOriginal a, b: " << a << ' ' << b;
A Function with Two Generic Types

#include <iostream>
using namespace std;
template <class type1, class type2>
void myfunc(type1 x, type2 y)
{
cout << x << ' ' << y << '\n';
}

int main()
{
myfunc(10, "I like C++");
myfunc(98.6, 19L);
return 0;
}
Explicitly Overloading a Generic Function

• Also called as explicit specialization

• The overloaded function overrides (or "hides")


the generic function relative to that specific
version.
// Overriding a template function. int main()
#include <iostream> {
using namespace std; int i=10, j=20;
template <class X> void swapargs(X &a, X &b) double x=10.1, y=23.3;
{ char a='x', b='z';
X temp; cout << "Original i, j: " << i << ' ' << j << '\n';
temp = a; cout << "Original x, y: " << x << ' ' << y << '\n';
a = b; cout << "Original a, b: " << a << ' ' << b << '\n';
b = temp;
cout << "Inside template swapargs.\n"; swapargs(i, j); // calls explicitly overloaded
} swapargs()
swapargs(x, y); // calls generic swapargs()
// This overrides the generic version of swapargs(a, b); // calls generic swapargs()
swapargs() for ints.
void swapargs(int &a, int &b) cout << "Swapped i, j: " << i << ' ' << j << '\n';
{ cout << "Swapped x, y: " << x << ' ' << y << '\n';
int temp; cout << "Swapped a, b: " << a << ' ' << b << '\n';
temp = a; return 0;
a = b; }
b = temp;
cout << "Inside swapargs int specialization.\n";
}
• Output:
Original i, j: 10 20
Original x, y: 10.1 23.3
Original a, b: x z
Inside swapargs int specialization.
Inside template swapargs.
Inside template swapargs.
Swapped i, j: 20 10
Swapped x, y: 23.3 10.1
Swapped a, b: z x
• // Use new-style specialization syntax.
template<> void swapargs<int>(int &a, int &b)
{
int temp;
temp = a;
a = b;
b = temp;
cout << "Inside swapargs int specialization.\n";
}
Overloading a Function Template
// Overload a function template declaration.
#include <iostream>
using namespace std;
// First version of f() template.
template <class X> void f(X a)
{
cout << "Inside f(X a)\n";
}
// Second version of f() template.
template <class X, class Y> void f(X a, Y b)
{
cout << "Inside f(X a, Y b)\n";
}
int main()
{
f(10); // calls f(X)
f(10, 20); // calls f(X, Y)
return 0;
}
Using Standard Parameters with Template
Functions
// Using standard parameters in a template
function. Output:
#include <iostream> This is a test
using namespace std;
const int TABWIDTH = 8; 100
// Display data at specified tab position. X
template<class X> void tabOut(X data, int
tab) 3
{
for(; tab; tab--)
for(int i=0; i<TABWIDTH; i++) cout << ' ';
cout << data << "\n";
}
int main()
{
tabOut("This is a test", 0);
tabOut(100, 1);
tabOut('X', 2);
tabOut(10/3, 3);
return 0;
}
Generic Function Restrictions

• Though they are similar to function


overloading, they do not cover functions
involving different set of instructions.
#include <iostream> int main()
#include <cmath> {
using namespace std;
void myfunc(int i) myfunc(1);
{ myfunc(12.2);
cout << "value is: " << i << "\n"; return 0;
} }
void myfunc(double d)
{
double intpart;
double fracpart;
fracpart = modf(d, &intpart);
cout << "Fractional part: " << fracpart;
cout << "\n";
cout << "Integer part: " << intpart;
}
Applying Generic Functions

• Used in implementation of algorithms.


A Generic Sort
// A Generic bubble sort. int main()
#include <iostream> {
using namespace std; int iarray[7] = {7, 5, 4, 3, 9, 8, 6};
double darray[5] = {4.3, 2.5, -0.9, 100.2, 3.0};
template <class X> void bubble( int i;
cout << "Here is unsorted integer array: ";
X *items, // pointer to array to be sorted
for(i=0; i<7; i++)
int count) // number of items in array cout << iarray[i] << ' '<< endl;
{ cout << "Here is unsorted double array: ";
register int a, b; for(i=0; i<5; i++)
X t; cout << darray[i] << ' '<< endl;
for(a=1; a<count; a++)
for(b=count-1; b>=a; b--) bubble(iarray, 7);
if(items[b-1] > items[b]) { bubble(darray, 5);
// exchange elements
cout << "Here is sorted integer array: ";
t = items[b-1]; for(i=0; i<7; i++)
items[b-1] = items[b]; cout << iarray[i] << ' '<< endl;
items[b] = t; cout << "Here is sorted double array: ";
} for(i=0; i<5; i++)
} cout << darray[i] << ' ' << endl;
return 0;
}
• Output:
Here is unsorted integer array: 7 5 4 3 9 8 6
Here is unsorted double array: 4.3 2.5 -0.9 100.2 3
Here is sorted integer array: 3 4 5 6 7 8 9
Here is sorted double array: -0.9 2.5 3 4.3 100.2
Generic Classes
template <class Ttype> class class-name {
.
.
.
}
class-name <type> ob;
// This function demonstrates a generic stack.
#include <iostream> if(tos==0) {
using namespace std; cout << "Stack is empty.\n";
const int SIZE = 10; return 0; // return null on empty stack
}
// Create a generic stack class tos--;
template <class StackType> class stack { return stck[tos];
StackType stck[SIZE]; // holds the stack }
int tos; // index of top-of-stack int main()
public: {
stack() { tos = 0; } // initialize stack // Demonstrate character stacks.
void push(StackType ob); // push object on stack stack<char> s1, s2; // create two character stacks
StackType pop(); // pop object from stack int i;
}; s1.push('a');
s2.push('x');
// Push an object. s1.push('b');
template <class StackType> void s2.push('y');
stack<StackType>::push(StackType ob) for(i=0; i<2; i++) cout << “\nPop s1: " << s1.pop() ;
{ for(i=0; i<2; i++) cout << "Pop s2: " << s2.pop();
if(tos==SIZE) { // demonstrate double stacks
cout << "Stack is full.\n"; stack<double> ds1, ds2; // create two double stac
return; ds1.push(1.1);
} ds2.push(2.2);
stck[tos] = ob; ds1.push(3.3);
tos++; ds2.push(4.4);
} for(i=0; i<2; i++) cout << “\nPop ds1: " << ds1.pop
// Pop an object. for(i=0; i<2; i++) cout << “\nPop ds2: " << ds2.pop
template <class StackType> return 0;
StackTypetack<StackType>:: pop() }
{
An Example with Two Generic Data Types
/* This example uses two generic data types in a class definition. */
#include <iostream>
using namespace std;

template <class Type1, class Type2> class myclass


{
Type1 i;
Type2 j;
public:
myclass(Type1 a, Type2 b) { i = a; j = b; }
void show() { cout << i << ' ' << j << '\n'; } Output:
};
10 0.23
int main() X Templates add power.
{
myclass<int, double> ob1(10, 0.23);
myclass<char, char *> ob2('X', "Templates add power.");
ob1.show(); // show int, double
ob2.show(); // show char, char *
return 0;
}
Applying Template Classes: Practical Benefits
A Generic Array Class

• Templates can be used to create safe arrays


when combined with operator overloading “[ ]”.
• It provides run-time boundary checking
• This is called as generic safe-array type
// A generic safe array example. cout << "Integer array: ";
#include <iostream> for(i=0; i<SIZE; i++) intob[i] = i;
#include <cstdlib> for(i=0; i<SIZE; i++)
using namespace std; cout << intob[i] << " ";
const int SIZE = 10; cout << '\n';
template <class AType> class atype { cout << "Double array: ";
AType a[SIZE]; for(i=0; i<SIZE; i++)
public: doubleob[i] = (double) i/3;
atype() { for(i=0; i<SIZE; i++)
register int i; cout << doubleob[i] << " ";
for(i=0; i<SIZE; i++) a[i] = i; cout << '\n';
} intob[12] = 100; // generates runtime error
AType &operator[](int i); return 0;
}; }
// Provide range checking for atype.
template <class AType> AType &atype<AType>::operator[ ] (int i)
{
if(i<0 || i> SIZE-1) {
cout << "\nIndex value of ";
cout << i << " is out-of-bounds.\n";
exit(1);
}
return a[i];
}
int main()
{
atype<int> intob; // integer array
atype<double> doubleob; // double array
int i;
Using Non-Type Arguments with Generic Classes

• non-type arguments can also be specified in template


specification.
• The syntax is same as for normal function parameters:
simply include the type and name of the argument.
• Non-type parameters are restricted to integers, pointers,
or references.
• non-type parameters are constants and their values
cannot be changed.
// Demonstrate non-type template arguments.
#include <iostream> int main()
#include <cstdlib> {
using namespace std; atype<int, 10> intob; // integer array of size 10
atype<double, 15> doubleob; /*double array of
// Here, int size is a non-type argument. size 15*/
template <class AType, int size> class atype { int i;
AType a[size]; // length of array is passed in size cout << "Integer array: ";
public: for(i=0; i<10; i++)
atype() {
intob[i] = i;
register int i;
for(i=0; i<10; i++)
for(i=0; i<size; i++) a[i] = i;
} cout << intob[i] << " ";
AType &operator[](int i); cout << '\n';
}; cout << "Double array: ";
for(i=0; i<15; i++)
// Provide range checking for atype. doubleob[i] = (double) i/3;
template <class AType, int size> for(i=0; i<15; i++)
AType &atype<AType, size>::operator[](int i) cout << doubleob[i] << " ";
{ cout << '\n';
if(i<0 || i> size-1) { intob[12] = 100; // generates runtime error
cout << "\nIndex value of "; return 0;
cout << i << " is out-of-bounds.\n"; }
exit(1);
}
return a[i];
}
Using Default Arguments with Template Classes

• A template class can have a default argument


associated with a generic type.
• For example,
template <class X=int> class myclass { //...
• non-type arguments can also take default arguments
// Demonstrate default template arguments. int main()
#include <iostream> {
#include <cstdlib> atype<int, 100> intarray; // integer array, size 100
using namespace std; atype<double> dbarray; // double array, default size
atype<> defarray; // default to int array of size 10
// Here, AType defaults to int and size defaults to 10. int i;
template <class AType=int, int size=10> class atype { cout << "int array: ";
AType a[size]; // size of array is passed in size for(i=0; i<100; i++)
public: intarray[i] = i;
atype() { for(i=0; i<100; i++)
register int i; cout << intarray[i] << " ";
for(i=0; i<size; i++) a[i] = i; cout << '\n';
} cout << "double array: ";
AType &operator[](int i); for(i=0; i<10; i++)
}; dbarray[i] = (double) i/3;
for(i=0; i<10; i++)
// Provide range checking for atype. cout << doublearray[i] << " ";
template <class AType, int size> cout << '\n';
AType &atype<AType, size>::operator[](int i) cout << "defarray array: ";
{ for(i=0; i<10; i++)
if(i<0 || i> size-1) { defarray[i] = i;
cout << "\nIndex value of "; for(i=0; i<10; i++)
cout << i << " is out-of-bounds.\n"; cout << defarray[i] << " ";
exit(1); cout << '\n';
} return 0;
} }
Explicit Class Specializations
// Demonstrate class specialization. int main()
#include <iostream> {
using namespace std; myclass<double> d(10.1);
template <class T> class myclass { cout << "double: " << d.getx() << "\n\n";
T x; myclass<int> i(5);
public: cout << "int: " << i.getx() << "\n";
myclass(T a) { return 0;
cout << "Inside generic myclass\n"; }
x = a;
}
T getx() { return x; } Output:
}; Inside generic myclass
double: 10.1
// Explicit specialization for int. Inside myclass<int> specialization
template <> class myclass<int> { int: 25
int x;
public:
myclass(int a) {
cout << "Inside myclass<int> specialization\n";
x = a * a;
}
int getx() { return x; }
};
The typename and export Keywords
• typename ->substituted for the keyword class in a template
declaration.
template <typename X> void swapargs(X &a, X &b)
{
.
.
.
}
• There is no difference between using class and using typename in
this context.
• to inform the compiler that a name used in a template declaration is
a type name rather than an object name.

• The export keyword precedes a template declaration, allows other


files to use the template already declared.
The Power of Templates

• Generic functions and classes provide a


powerful tool that you can use to amplify your
programming efforts.
• Reusability
• Easy debugging
• Provides an added layer of abstraction.
• C++ has a STL (Standard Template Library)

You might also like