Sei sulla pagina 1di 27

C++ Templates

and Generic Programming

Folien von Eugene A. Zueff (mit kleinen Aenderungen)

ETH Zuerich 2001

Webseiten: http://www.inf.ethz.ch/~zueff

23.10.2001, Lecture 1 1 of 30

C++ Templates
and Generic Programming
Overall Plan:
Part One: Template Mechanism in C++
Part Two: Technique Examples; Metaprogramming
Part Three: Introduction to Generic Programming
with Examples; STL Library
Detailed Plan:
Will be given for every lecture

23.10.2001, Lecture 1 5 of 30
C++ Templates
and Generic Programming
Literature:
ISO/IEC International Standard – C++
ISO/IEC 14882, 1998(E)
“Draft” Standard (publicly available) of Dec 1996.
www.cygnus.com/misc/wp/dec96pub
B. Stroustrup
The C++ Programming Language
Third Edition, AT&T 1997.
Leen Ammeraal
STL for C++ Programmers
John Whiley and Sons, Ltd., 1997.
ISBN: 0471971812.
23.10.2001, Lecture 1 6 of 30

C++ Templates
and Generic Programming

Plan for Today:


• Introduction to Templates
• Function Templates
• Template Instantiation
• Explicit and Implicit Instantiation
• Type & Non-type Template Parameters

23.10.2001, Lecture 1 7 of 30
Introduction to Templates: The Very First Example

int Max ( int a, int b )


{
return a>b ? a : b;
}

Problems if a program is (really) large:


• Several functions for calculating maximum
for different parameter types
(floats, doubles etc.).
• Functions for calculating “maximum”
for user-defined types.

23.10.2001, Lecture 1 8 of 30

Introduction to Templates: The Very First Example

Comment: Size and Complexity


(The size does matter ☺)
• Small independent program:
we don’t need any programming technique at all
• Large and complex program:
we need a very powerful and advanced
programming technique
• “Small” and “large” program:
of about 1000 lines of code.

23.10.2001, Lecture 1 9 of 30
Introduction to Templates: The Very First Example

Straightforward Decision:
Define specific Max functions for all types
used in the program.
float Max ( float a, float b )
{
return a>b ? a : b;
}
double Max ( double a, double b )
{
return a>b ? a : b;
}
UT1 Max ( UT1 a, UT1 b )
{
UT1, UT2 – return a>b ? a : b;
user-defined }
types UT2 Max ( UT2 a, UT2 b )
{
return a>b ? a : b;
}
23.10.2001, Lecture 1 10 of 30

Introduction to Templates: The Very First Example

Straightforward Decision:
Define specific Max functions for all types
used in the program.

Why not?
• Very hard to maintain (i.e., to test & debug,
to prove correctness, to modify etc.).
• Impossible: type may be unknown beforehand
(e.g. in a case of a library).

23.10.2001, Lecture 1 11 of 30
Introduction to Templates: The Very First Example

Let “T” to denote


“any type”

T Max ( T a, T b )
{
return a>b ? a : b;
}

23.10.2001, Lecture 1 12 of 30

Introduction: Template Declaration

Keywords
Template Type
Parameter

template < typename T > Template Header


T Max ( T a, T b )
{ Template Body
return a>b ? a : b;
}

23.10.2001, Lecture 1 13 of 30
Introduction: Template Declaration

Important problems to make clear:


How to use a template?
Template instantiation
Template invokation
Some rules on using templates
Requirements on actual types
Is there any other way to specify function patterns?
Templates and macros

23.10.2001, Lecture 1 14 of 30

Introduction: Using Function Templates

The general question:


How to use function template?
The general answer:
Just like ordinary functions!

template < typename T >


Example: T Max ( T a, T b )
Use Max function {
template to return a>b ? a : b;
}
calculate maximum
of two values of double x, y, res;
type double:
double // assigning some values to x & y

res = Max(x-1,y+2.5);

23.10.2001, Lecture 1 15 of 30
Introduction: How It Works

Function template
Original call
template < typename T >
T Max ( T a, T b ) res = Max(x-1,y+2.5);
{
return a>b ? a : b;
}

Template Instantiation

double Maxdouble ( double a, double b )


{
return a>b ? a : b;
}
Function-by-template
Result call
res = Maxdouble(x-1,y+2.5);
23.10.2001, Lecture 1 16 of 30

Introduction: How It Works

Remarks:
• All the job is performed automatically by a C++ compiler
(this is the requirement of the Standard, i.e.,
this is the part of the language’s semantics).
• Compiler decides which actual types to substitute
to the function-by-template instead of formal type(s)
by analyzing the argument types from the call.

23.10.2001, Lecture 1 17 of 30
Introduction: How It Works

Remarks (continued):
• Template instantiation for a specific type is performed
only once.
Example: for the following two calls

res = Max(x-1,y+2.5);
res = Max(1.0,res);

the compiler will generate only one copy of Maxdouble


function, and will use it to generate code for both calls.

23.10.2001, Lecture 1 18 of 30

Introduction: How It Works

Remarks (continued):
• Template instantiation is performed for every specific set
of the actual types.
Example: for the following two calls

res = Max(x-1,y+2.5);
int k = Max(1,(int
int)res);
int

the compiler will generate two functions-by-template:


Maxdouble for the first call, and Maxint for the second one.

23.10.2001, Lecture 1 19 of 30
Introduction: How It Works

Three major conclusions:


• The compiler makes all the instantiating job.
• The types of actual function arguments are used
as actual types for template instantiating.
• The result type of the function is not considered
while instantiating.

23.10.2001, Lecture 1 20 of 30

Template Instantiation: The General Steps

f(actual-arguments)

1. If f is the usual function, then go to 3.


2. If f is the function template then
2.1 Determine the set {Ti} where Ti is the type
of the i-th actual-argument.
2.2 If the function-by-template of form f{Ti} already exists
then go to 3.
2.3 Generate function-by-template f{Ti} using type Ti as the
substitution for the i-th formal type for the f template.
2.4 Compile the function-by-template f{Ti} generated on the
previous step.
3. Generate code for the function call.
23.10.2001, Lecture 1 21 of 30
m v

Template Instantiation:
do A Problem for Future

// This template serves as a single means


// for generating an arbitrary value of any type
ran T >
template < typename
T any ( void )
{
return a ;
}

But how to call this template?


int i = any(); // is it correct?

The question is:


how can the compiler determine the type to use
as the actual type while instantiating the template?

23.10.2001, Lecture 1 22 of 30

Template Instantiation: Requirements on Types


Taking the very first example again…
template < typename T >
T Max ( T a, T b )
{
return a>b ? a : b;
}

Let’s introduce a user-defined type…


class C {
int m;
public:
public
C(): m(0) { }
};

…and apply our template to (the objects of) this type:


C c1, c2;
...Max(c1,c2)... What will happen?
23.10.2001, Lecture 1 23 of 30
Template Instantiation: Requirements on Types
Let’s consider the function-by-template the compiler
generates while processing the call Max(c1,c2):

// Generated by compiler
C MaxC ( C a, C b )
{
return a>b ? a : b;
}

Is this function correct?- No.


Error message occurs
(Microsoft Visual Studio C++ Compiler):
binary ’>’:
’class C’ doesn’t define this operator or...

23.10.2001, Lecture 1 24 of 30

Template Instantiation: Requirements on Types

The reason:
Class C must have the operator for making
the comparison of two objects of type C.

// Generated by compiler
C MaxC ( C a, C b )
{
return a>b ? a : b;
}

But there is no such operator for our C type!


Hence we cannot apply Max template for
objects of type C.

23.10.2001, Lecture 1 25 of 30
Template Instantiation: Requirements on Types

Add the ‘>’ operator to our C class:

class C {
int m;
public:
public
C(): m(0) { }
bool operator > ( C& c )
{
return m > c.m;
}
};

Now it works.

23.10.2001, Lecture 1 26 of 30

Template Instantiation: Requirements on Types

Major conclusions:
1. It is possible to apply a template to objects of some type (either built-in
or user-defined type) if and only if this type contains all operators which
the template uses for objects of this type.
2. It is the good practice to specify requirements on actual type parameters
of a template, for example:

// This function template implements the common case of


// calculating maximum.
// Actual type for the template instantiation should have
// ‘>’ operator defined.
template < typename T>
T Max ( T, T );
3. A common conclusion for class developers:
While designing a class you should try to provide all operators
which may be necessary for its use.

23.10.2001, Lecture 1 27 of 30
Templates or Macros?

What’s the difference between templates and macros,


and why are templates better?

// Template representation
template < typename T >
T Max ( T a, T b )
{
return a>b ? a : b;
}

// ”Traditional” representation
#define Max(a,b) ((a)>(b)?(a):(b))

23.10.2001, Lecture 1 28 of 30

Templates or Macros: A Comparison


Macros Templates

Status: Not a part of the language: Templates are the “first-class”


preprocessing facilities form part of the C++ language;
a separate set of concepts template mechanism is
which is not related to other type-oriented and integrated
language concepts. with the type system.

How to activate Function call syntax

Implementation Direct text substituting Compilation with full syntax


without any syntax checks. checks for template declarations
and template use.

Type Checks No type checking at all Full semantic control including


type checks.
Run-time No extra run-time costs As effective as usual functions;
effectiveness as effective as macros if using
with inlining mechanism.

23.10.2001, Lecture 1 29 of 30
Templates or Macros: Examples

Code Max is Macro Max is Template

char*
char p; No errors on compile time; Error message because
Max(p,1000); the result hardly makes sense. template declaration for Max
Also the result is of a statically requires the actual arguments
unknown type. The program is to be of the same type.
non-reliable and non-portable.

Max(++x,--y) Either value of x or y will be The values of x and y will be


increased twice (because of increased only once before
direct text substituting). calling Max (just as for usual
Most likely this is not the effect function call).
a programmer expects.

23.10.2001, Lecture 1 30 of 30

C++ Templates
and Generic Programming

Lecture 2
-

30.10.2001, Lecture 2 1 of 30
C++ Templates
and Generic Programming

Lecture 1: To Remind
• Function Template – A Family of Functions
• Template Type Parameters
• Template Instantiation
Lecture 2: Plan for Today
• Class Template – A Family of Types
• Class Template Instantiation
• Type and Non-Type Template Parameters
• Explicit Instantiation for Function Templates
30.10.2001, Lecture 2 2 of 30

Class Templates: The First Example

Stack, or LIFO Memory


Usual set of the operators on stack:
• Push a new element (value) into stack
• Pop the uppermost element from the stack
• Check if the stack is empty
• ...

Push a new element Pop the uppermost


into stack element from the
stack

Stack Top The uppermost element

30.10.2001, Lecture 2 3 of 30
Class Templates: The First Example

Implementation in C++: Non-Template Case


Stack of integer values (array-based implementation)
class Stack
{
// implementation
int top;
int S[100];
public:
public
// interface
Stack() : top(-1) { }
void push ( int V ) { S[++top] = V; }
int pop (void
void)
void { top--; return S[top+1]; }
// other operations
. . .
}
30.10.2001, Lecture 2 4 of 30

Class Templates: The First Example

Implementation in C++: Solution with Templates


Stack of objects of any type (array-based implementation)
template < typename T >
class Stack
{
// implementation
int top;
T S[100];
public:
public
// interface
Stack() : top(-1) { }
void push ( T V ) { S[++top] = V; }
T pop (void
void)
void { top--; return S[top+1]; }
// other operations
. . .
}
30.10.2001, Lecture 2 5 of 30
Class Templates: The First Example

Implementation in C++: Solution with Templates


Stack of objects of any type (array-based implementation)
template < typename T >
class Stack
{
// implementation
int top; Are there any design lacks
T S[100]; in this implementation?
public:
public .
// interface
Stack() : top(-1) { }
void push ( T V ) { S[++top] = V; }
T pop (void
void)
void { top--; return S[top+1]; }
// other operations
. . .
}
30.10.2001, Lecture 2 6 of 30

Class Templates: Implementation in C++

• A class is a type (Std, Chapter 9)


• A class template is not a type;
it is a family of types
• A function template is not a function;
it is a family of (overloaded) functions

30.10.2001, Lecture 2 7 of 30
Class Templates: Implementation in C++

Almost the same problems as for Max template:


• How to use the Stack template?
(I.e., how to make classes from the class template?)
Class template instantiation
• Which are the requirements on the actual types?
Appropriate set of operators
• Optimizing the template
How to weaken the requirements
on the actual types?
• Improving the template
More generality!
30.10.2001, Lecture 2 8 of 30

Class Template Instantiation

Template Instantiation: Conceptual Scheme

Class Template C
with Formal Type
Parameters T1 … Tn
Class by Template
C IJ1 … IJn
Actual Type
Parameters
IJ1 … IJn

30.10.2001, Lecture 2 9 of 30
Class Template Instantiation

Template Instantiation: Example and Syntax

Class Template
Stack with Formal
Type Parameter T
Class by Template
Stack<int>
Actual Type
Parameter
int

30.10.2001, Lecture 2 10 of 30

Class Template: Instantiation & Use

template < typename T >


class Stack
{
Template Declaration
// implementation
. . .
public:
public
// interface
Stack() : top(-1) { }
void push ( T V ) { S[++top] = V; }
T pop (void
void)
void { top--; return S[top+1]; }
}

Template Name

Stack<int
int>
int Template Instantiation

Actual type

30.10.2001, Lecture 2 11 of 30
Class Template: Instantiation & Use

Declaration

Object Declaration
Stack<int
int>
int sint;

Type Specifier Declarator

30.10.2001, Lecture 2 12 of 30

Class Template: Instantiation & Use

More examples of template instantiations:


Stack<float
float>
float sf1, sf2;

Stack<int
int>*
int ArrayOfStacks[10]; ? Oder Array von Textpointern ? D.S.

typedef Stack<double
double>
double SD;
SD sd1, sd2;

How to use object of class-by-template type:


Stack<int
int>
int s;
. . .
s.push(1);
. . .
int from_top = s.pop();

30.10.2001, Lecture 2 13 of 30
Class Templates: Major Conclusions

• Class template is not a type but a family of types;


we should instantiate the template before using it as a type.
• Instantiating the class template means generating
the new class-by-template by replacing formal types
for corresponding actual types.
• We should always use the notation of explicit template
instantiation in order to make a class-by-template:
template-
template-name < actual- actual-types >
(there is no implicit instantiation for class templates).
• After instantiating the construct of template instantiation
denotes a class-by-template generated by compiler.
• Class-by-template behaves just as an ordinary class and
may be used everywhere as a type.
30.10.2001, Lecture 2 14 of 30

Class Templates: Requirements on Actual Types

template < typename T >


class Stack Which operators of formal type
{ are used whithin the template?
// implementation
. . .
public:
public
// interface
void push ( T V ) { S[++top] = V; }
. . .
}

Passing an object of type T


as parameter:
Copy constructor Copying one object of type T
to another:
Assignment operator

30.10.2001, Lecture 2 15 of 30
Class Templates: Requirements on Actual Types
So, this is the conclusion:
• If we want to apply our Stack template to a user-defined
type (i.e., to create a stack of class-type objects)
then we should provide copy constructor and assignment
operator in the class.
In other words:
• The requirement on the actual type from the Stack
template is that the actual type should always have
- public copy constructor and
- public assignment operator.
But:
Compiler automatically generates copy ctor & assignment
for every class. Does it mean that we don’t care about it?
30.10.2001, Lecture 2 16 of 30

Class Templates: Requirements on Actual Types


The following problems with copy constructor may occur:
• Copying objects while passing them as parameters
my be very time-consuming action.
• Copying objects while passing them as parameters
may be simply impossible:
class C {
private:
private
C ( C& c ) { . . . }
. . .
};

A class developer doesn’t allow objects of type C


to be passed as parameters.

30.10.2001, Lecture 2 17 of 30
Class Templates: Requirements on Actual Types
Hence there are direct reasons to weaken the requirement
on the actual type from the Stack template.
template < typename T >
class Stack
{
// implementation
. . .
public:
public
// interface
void push ( T& V ) { S[++top] = V; }
. . .
}

Now not a value but the reference to a value


is passed as a parameter
(passing-by-reference in some other languages);
The copy constructor will not be invoked
while passing the reference.

30.10.2001, Lecture 2 18 of 30

Class Templates: Requirements on Actual Types


Hence there are direct reasons to weaken the requirement
on the actual type from the Stack template.
template < typename T >
class Stack
{
// implementation
. . .
public:
public
// interface
void push ( T& V ) { S[++top] = V; }
T pop (void
void)
void { top--; return S[top+1]; }
. . .
}

C++: returning a value from a function


normally means copying it…
How to overcome this problem?
See Task 2.
30.10.2001, Lecture 2 19 of 30
Improving the Template
template < typename T >
class Stack
{
// implementation
int top;
T S[100];
public:
public
// interface
Stack() : top(-1) { }
void push ( T& V ) { S[++top] = V; }
T pop (void
void)
void { top--; return S[top+1]; }
// other operations
. . .
}

Is it possible to make the template


more generic?
30.10.2001, Lecture 2 20 of 30

Improving the Template


template < typename T >
class Stack
{
// implementation
int top;
T S[100];
public:
public
// interface
Stack() : top(-1) { }
void push ( T& V ) { S[++top] = V; }
T pop (void
void)
void { top--; return S[top+1]; }
// other operations
. . .
}

To parametrize not only the type of


stack elements but its size as well!
30.10.2001, Lecture 2 21 of 30
Improving the Template: Non-Type Parameters
template < typename T, int N >
class Stack
{
// implementation
int top;
T S[N];
public:
public
// interface
Stack() : top(-1) { }
void push ( T& V ) { S[++top] = V; }
T pop (void
void)
void { top--; return S[top+1]; }
// other operations
. . .
Template non-type parameter’s
} syntax has the form of an ordinary
declaration (or, which is the same,
the form of an ordinary function
parameter declaration).
30.10.2001, Lecture 2 22 of 30

Improving the Template: Non-Type Parameters


How to use the template with non-type parameter(s):
Stack of (maximum) ten integers:
Stack<int
int,10>
int s10int;
Common requirement:
• Template arguments should be processed during
compile time.
Possible kinds of non-type arguments
(as a consequence of the previous point):
• Constant expression of an integral or enumeration type;
• Name of an object of function with external linkage
(i.e., a non-local object or non-static object/function);
• Address of an object of function with external linkage.

30.10.2001, Lecture 2 23 of 30
Template Instantiation: A Problem for Future

// This template serves as a single means


// for generating an arbitrary value of any type
template < typename T >

re
T any ( void )

tu
{

ec
return a random value of type T;

sl
}

iou
ev
But how to call this template?

pr
e
int i = any(); // is it correct?

th
mo
The question is:

Fr
how the compiler can determine the actual type
while instantiating the template?

30.10.2001, Lecture 2 24 of 30

Template Instantiation: A Problem for Future


More substantial, but conceptually similar example:
the function calculating the number of 32-bit words
for an arbitrary type.
template < typename T >
int spaceOf ( void )
{
int bytes = sizeof T;
return bytes/4 + bytes%4>0;
}

How to call this template?

int w = spaceOf(); // is it correct?

The question remains the same:


how the compiler can determine the actual type
while instantiating the template?
30.10.2001, Lecture 2 25 of 30
Explicit Instantiation of Function Templates

The solution is to use explicit instantiation


(exactly as for class templates)
i.e. explicitly specify the function template arguments.

class C { . . . }; // class declaration; C – class type


typedef void (*pf)(int
int);
int // pf is pointer-to-function type

int wint = spaceOf<int


int>();
int
int wC = spaceOf<C>();
int wpf = spaceOf<pf>();
int warr = spaceOf<int
int[10]>();
int

30.10.2001, Lecture 2 26 of 30

Explicit Instantiation of Function Templates


Let’s consider how explicit instantiation works
template < typename T > Original call
int spaceOf ( void ) int wint = spaceOf<int
int>();
int
{
int bytes = sizeof T;
return bytes/4 + bytes%4>0;
}

int spaceOfint ( void ) int wint = spaceOfint();


{ Instantiation
int bytes = sizeof int;
int
return bytes/4 + bytes%4>0;
}

int spaceOfint ( void ) int wint = 1;


{ Optimization
return 1;
} Optimization
30.10.2001, Lecture 2 27 of 30

Potrebbero piacerti anche