Templates

Document Sample
Templates
[ Templates ]

Adapted from http://www.cs.washington.edu/people/acm/tutorials

The immortal question: Why?

What exactly are templates for, and why learn them?





• Limited Generic Programming (polymorphism)

Some functions have the same semantics for some (if not all) data

types. For instance, a function print() should display a sensible

representation of anything passed in. Ideally, it shouldn’t need to be

rewritten for each possible type.



• Less repetitive code

Code that only differs in the data type it handles does not have to be

rewritten for each and every data type you want to handle. It’s easier to

read and maintain since one piece of code is used for everything

Example: a swap function

Problem: Oftentimes, it is nice to be able to swap the values of two

variables. This function’s behavior is similar for all data types. Templated

functions let you do that – in most cases without any syntax changes.



Stupid method – write an overloaded function for each type

Swap for integers Swap for an arbitrary type T

void swap(int &a, int &b) { void swap(T &a, T &b) {

int c = a; T c = a;

a = b; a = b;

b = c; b = c;

} }





Template method – write one templated function

template This function can be used with any

void swap(T &a, T &b) { type that supports assignment and can

T c = a; be passed in as a non-const reference.

a = b;

b = c;

}

Template Syntax: swap dissected

The template line states that

everything in the following Here we have a list of “placeholder

declaration or definition is under variables.” In almost all cases, they

the subject of the template. (In this will be specified with either the

case, the definition is the function typename or class keywords.

swap) These two keywords are

equivalent.





template

void swap(T &a, T &b) {

T c = a;

a = b;

b = c;

}





“Placeholder variables” have one value

within each template declaration. Think of

them as being replaced by whatever type

you specify the template to be.

Template Syntax: Using it

Using a template template

To use a template, one has to specialize void swap(T &a, T &b) {

it. This is why it isn’t quite a generic T c = a;

function. It does static polymorphism. It a = b;

morphs itself to the right type at b = c;

preprocess time (explained later!). }



Syntax

To explicitly specialize a template, write its name with the arguments for the

placeholder variables in angle brackets. This method always works.

Example:

double d1 = 4.5, d2 = 6.7;

swap(d1, d2);

Templates however can auto-sense their placeholder values if all information

about what the placeholders represent can be inferred from the context

(arguments, and for member functions, the associated class instance). This is

called implicit specialization. In the previous case, the compiler is smart

enough to figure out that T is a double even without the explicit

since the arguments are doubles. Thus this shorthand works:

Example:

swap(d1, d2);

How they Work: Compilation 101

Preprocessor Libraries

Resolves #define, #include,

Source code .c .h .c .h

comments, templates

(text)

Preprocessor

Compiler

Translates code to Machine C/C++ code

(text)

Language. It outputs an “object Compiler

file.” This code is not executable Object code

(bin)

Linker

Linker

Takes object files and resolves

references to functions and Native Executable executable

variables in different files (bin)







When you build an executable from a C++ source file, the preprocessor removes

all the things listed under “Preprocessor.” The result is pure C++ code (no

comments, templates, #includes, etc). This code is then compiled and linked.

All good programmers understand this process well.

How they Work: Compiler, Linker







What does it mean to compile?

• The term “compile” is somewhat ambiguous. Often, when people say

“compile” they mean “build.” In the formal sense, it means turning one

language into another language. With C++, this generally means turning

C++ source code into Machine Code.

• Each C++ source file is usually compiled into an object file that contains the

code of all its defined functions. At this point, if you call a function from a

library or another file, the object code (stuff in the object file) only says “this

function exists somewhere and I want to use it”

• This if formally what the compiler is. When you get syntax errors, this is

usually the compiler talking to you (as opposed to the linker or preprocessor).

How they Work: Compiler, Linker









What does it mean to link?

• After compilation happens, all the object files need to be linked together into

a final executable. All “I want this function” stubs in the object files have to

actually be resolved to some block of machine code and then the resulting

executable has to be formatted in a way the operating system can understand.

• If you write a prototype for a function, but forget to define it, your code will

compile but it won’t link. Link errors are usually harder to track, as the

linker can’t always give you line numbers (the linker only looks at the object

files and knows nothing about the original source).

How they Work: Preprocessor

What is the preprocessor?

The preprocessor, formally, deals with the directives that start with a # sign (like

#include, #define). However, here, the term will be used to mean everything

that happens before the compiler gets the stuff to turn into machine code.

The relevant (in relation to templates) things the preprocessor does are:

• Replaces all #include statements and with the files they refer to.

• Removes all comments.

• Replaces all #defines macros with their value

• Generates actual code from templates

Templates do not exist!

• Templates are a preprocessor construct. They are cookie-cutters with which

the preprocessor generates real C++ code. When a template is used, (that

is, specialized, implicitly or explicitly), it get instantiated.

• The instantiation tells the preprocessor to create a version of the template

where each placeholder is replaced by its specialization. At this point, the

specific version of the template comes into existence and can be compiled. It

does not exist otherwise!

• In a very real way, a template just does a search and replace for each type you

specialize the template for. In essence, you are doing the same as writing a

bunch of overloaded functions. It’s just done for you, behind your back.

How they Work: Consequences







Problem:

Templates are resolved in the preprocessing stage, so they don’t exist to

the compiler until they get instantiated. This is the balance between trying

to make templates work transparently, and trying to make things efficient.







Effects:

• Template code will not get compiled until used (and thus instantiated).

Thus, the compiler will not catch syntax errors until the template is used.

• This holds at the level of individual methods. They are not compiled

unless they are used.

Class Templates: Class Definition

Syntax:

Templated classes basically follow the same syntax as templated

functions. However, the rules for which templated classes can infer their

specialization (see Template Syntax) are a bit more convoluted.



Before moving on, a bit of review on templated functions:

Are the following two templates equivalent?

template template

void swap(T &a, T &b) { void swap(C &a, C &b) {

T c = a; C c = a;

a = b; a = b;

b = c; b = c;

} }



Answer:

Yes, they are equivalent. This may be relevant when writing class

templates as it is possible that a situation may arise where two definitions

are written for the same thing. If this happens, the program will not build

since there are two equivalent function definitions. The name of the

placeholder doesn’t matter, and “typename” and “class” can be used

interchangeably. Just something to remember.

Class Templates: Example

Example: A templated, dynamic, 2 dimensional array (Matrix)*

#ifndef MATRIX_H

Notice the only addition to #define MATRIX_H

the class definition is the

line: template

template class Matrix {

public:

Matrix(int rows, int cols);

Matrix(const Matrix &other);

Within the the virtual ~Matrix();

definition

block, the Matrix& operator=(const Matrix &rhs);

T* operator[](int i);

placeholder T can int getRows() const;

be used as a data int getCols() const;

type. When the

protected:

template is void copy(const Matrix &other);

specialized, it

takes on the value private: The header is pretty

of the Matrix(); pedestrian. Let’s have

int m_rows;

specialization. some fun. 

int m_cols;

T *m_linArray; On to the class

}; implementation.

File: Matrix.h #endif /* MATRIX_H */



*A commented version of this code is provided separately. It wouldn’t fit on the slide. 

Class Templates: Example cont’d

#include "Matrix.h" template

T* Matrix::operator[](int i) {

template return m_linArray + (i*m_cols);

Matrix::Matrix() }

{}

template

template void

Matrix::Matrix(int rows, int cols) { Matrix::copy(const Matrix &other) {

m_rows = rows; m_rows = other.m_rows;

m_cols = cols; m_cols = other.m_cols;

m_linArray = new T[m_rows * m_cols];

} int size = m_rows * m_cols;

m_linArray = new T[size];

template for( int i=0; i ::Matrix(const Matrix &other) { m_linArray[i] =

copy(other); other.m_linArray[i];

} }

}

template

Matrix::~Matrix() { template

delete[] m_linArray; int Matrix::getRows() const {

} return m_rows;

}

template

Matrix&

Matrix::operator=(const Matrix &other) { template

if( this != &other ) { int Matrix::getCols() const {

delete[] m_linArray; return m_cols;

copy(other); }

}

The next slide explains

return *this; all this. It wouldn’t fit

} File: Matrix.cc on this slide. 

Class Templates: Member Functions Dissected

Again, a templated class name by itself

has no meaning (eg. Matrix by itself Here, the template has been

means nothing). It only gets meaning implicitly specialized by its context.

through specialization, explicit or implicit. It is within the specialization region

Thus, when referring to an instance of a of the class scope. Thus it does not

templated class (a specific need the template arguments. For a

specialization), the class name must be class definition, the specialization

explicitly specialized. region is the class block.



template

Matrix&

Matrix::operator=(const Matrix &other) {

if( this != &other ) {

this->~Matrix(); This may be

copy(other); obvious, but

}

remember that

return *this; though constructors

} and destructors

Notice that the specialization region of have the same name

specialization Matrix:: as a the class

template, they are

region does not include the functions and do not

return type. Thus the return need to be

type needs explicit specialized.

specialization

Class Templates: Dark Arts (usage)

Syntax

• Templated classes must be explicitly specialized. Thus, to create a 2

dimensional Matrix of doubles using the last example, the syntax would be:

Matrix m(3,3);



• This specialization during declaration in reality creates a new type – namely

Matrix. This should be thought of as its own type, separate from

any other specialization of Matrix (so it is different from Matrix, or

Matrix, etc.) At this point, the instance behaves as any other

instantiated type – at least for compilation.



Now that you have the basics…

So, young Jedi, you want to become a template master. You think you know all the

tricks. Little do you know, your programming life now hangs in the balance. For

what comes next is the real lesson. The coming information is what makes people

shiver in fear when the word template is mentioned. Listen to what is presented

next closely lest the subtleties stay shrouded in shadows. Now is time to learn of

convention, for once you break from convention, you enter the dark side of

template hell, and forever shall it dominate your path… Mu ha ha ha

Shotgun Safety: Danger Awareness

(Identifying the danger)

Problem

Templates do not exist until you use them. They must be instantiated. Unless

this is done explicitly, instantiation occurs at the first usage for all known

template definitions. Thus, consider this example. Compile with

g++ -Wall –ansi main.cc Matrix.cc

Looks innocent, but it won’t link. /* main.cc */

#include

Quiz: What won’t link and why? using namespace std;



The link error happens with m1.getRows() #include “Matrix.h”



• Nothing from a template gets instantiated int main(void) {

until it is either used or explicitly Matrix m1(3,4);

instantiated. cout ::getRows() const }

does not get created until it is used at the

line with m1.getRows(). Note: The compile line is actually wrong!

• The definition of the function is in Matrix.cc The file Matrix.cc only contains template

and never used there. code. Since it is never used, it never

• Thus the definition never gets created and generates object code and shouldn’t be

compiled to object code. compiled.

Shotgun Safety: 3 conventions

(know the routines)



There are three conventions to avoiding the link problem

• Write all the code inline in the .h files.

• Do the same as above, but kind of fake it by writing an implementation

file with your implementation and #include the implementation file in

your header file.

• Write the template as you would a normal class (using a header and an

implementation file). Then create a new source file and #include the

template implementation file there. This is the file which you

compile, not the template implementation. (See next slide for example)



The first two methods have the problem that anytime an implementation of a

function is changed, all code that uses it must be recompiled (not just

relinked). This is very slow on large builds. Also, the build process will

instantiate the template many more times than necessary which is a waste of

time and space. The third method is free from such problems. It also avoids

some other hurdles since it forces the instantiation of everything at one point.

Shotgun Safety: An example

(faithfully practiced, prevents accidental loss of feet)

The proper procedure

/* main.cc */ • Write the template, separated into a

#include header and an implementation file

using namespace std;

• Create an instantiation file for the

#include template which include the

int main(void) {

implementation file.

Matrix m1(3,4); • Compile the instantiation file and not

cout ;



This line forces the instantiation of the Matrix class

compile line: template, as well as all its member functions, for

g++ –Wall –ansi main.cc MatrixInst.cc specialization int. Other specializations require their

own lines.

Poison detection: Pop Quiz

(be aware, so you know before it’s too late)

/*Foo.h */ Will this compile?

#ifndef FOO_H

• The unfortunate answer is yes, it will

#define FOO_H

compile. Even though b is

undeclared, it will “compile” because

template

nothing actually instantiates the

class Foo {

template, so the compiler never sees

Foo() {

the template code.

b = “Hello Mom!”;

} • This is why not explicitly forcing the

}; instantiation of class templates is

dangerous. You won’t know about an

#endif /* FOO_H */ error until you use it.



Because of this, some people believe that it is better to write a non-templated

version of a class first, and then make a template from that. Some

beliefs, however, are just wrong. That is one of them.

If templates are done properly with forced instantiation (see previous

slide), then this scenario will not occur.


Share This Document


Related docs
Other docs by alllona
Contingency Plan Template
Views: 337  |  Downloads: 19
Buyer Beware - Web Design Templates
Views: 47  |  Downloads: 2
Timeframe, lesson plan template
Views: 39  |  Downloads: 2
Process and Organizational Change Plan Template
Views: 155  |  Downloads: 13
Corporate Design PowerPoint Templates
Views: 28  |  Downloads: 2
The Dean One-Page Plan template
Views: 174  |  Downloads: 5
SERVICE IMPROVEMENT PLAN TEMPLATE
Views: 1022  |  Downloads: 15
Microsoft PowerPoint - templates.ppt
Views: 3  |  Downloads: 0
by registering with docstoc.com you agree to our
privacy policy

You are almost ready to download!

You are almost ready to download!