Anda di halaman 1dari 8

Chapter 17

An Overview of Templates

We have already seen data types involving angle brackets, such as


vector<double>␣v;

Code involving angle brackets is written using a C++ language feature


called templates. In this chapter we will give a brief overview of how to write
template functions and classes.
Templates are quite a difficult subject in practice. We have already said
that you can think of C++ as consisting of three languages: C, an object-
oriented language, and the language of templates. Learning a new language
is a significant undertaking. For this reason we will only describe the basic
ideas of template programming in this chapter. You should consult another
reference such as [17] if you wish to write your own template library.

17.1 Template functions


Consider the following code to compute the maximum of a pair of numbers.
inline␣double␣findMax(␣double␣x,␣double␣y␣)␣{
␣␣␣␣if␣(x<y)␣{
␣␣␣␣␣␣␣␣return␣x;
Copyright © 2016. CRC Press. All rights reserved.

␣␣␣␣}␣else␣{
␣␣␣␣␣␣␣␣return␣y;
␣␣␣␣}
}

inline␣float␣findMax(␣float␣x,␣float␣y␣)␣{
␣␣␣␣if␣(x<y)␣{
␣␣␣␣␣␣␣␣return␣x;
␣␣␣␣}␣else␣{
␣␣␣␣␣␣␣␣return␣y;
␣␣␣␣}
}

295
Armstrong, J 2016, C++ for Financial Mathematics, CRC Press, Boca Raton. Available from: ProQuest Ebook Central. [21 August 2017].
Created from uts on 2017-08-21 16:39:23.
296 C++ for Financial Mathematics

This code violates the Once and Only Once principle because we have written
essentially the same function twice, the only difference is that the types are
different in the different function declarations.
Templates provide a solution to this problem. The following single template
function allows us to find the maximum of either doubles or floats.
template ␣ < typename ␣T >
inline ␣ T ␣ findMax ( T ␣x , ␣ T ␣ y ) ␣ {
if ␣ ( x ␣ <␣ y ) ␣ {
return ␣ y ;
}
else ␣ {
return ␣ x ;
}
}

When you write a templated function, you don’t specify all the types
of the parameters to your function. Instead, you provide a list of dummy
variables, called template parameters, which can be replaced as necessary
with the required types. In this example, we have one template parameter
and it is called T.
In our example we specify that we are writing a template function and it
has a template parameter called T, by writing:
template ␣ < typename ␣T >

The remaining code in our template function is then a copy of the desired
code to compute the maximum but using the dummy variable T to represent
the type.
We can then use our findMax function equally well with any type that
provides an implementation of <. This includes float, double but also int
and even string. This is tested using the following code:
void ␣ testMax () ␣ {
Copyright © 2016. CRC Press. All rights reserved.

ASSERT ( ␣ findMax (3 , ␣ 1)==3); ␣ // ␣ ints


ASSERT ( ␣ findMax (2.0 , ␣ 3.0) ␣ == ␣ 3.0); ␣ // ␣ doubles
ASSERT ( ␣ findMax ( ␣ string ( " ant " ) ,
string ( " zoo " )) ␣ == ␣ string ( " zoo " ));
}

One unusual feature of templated functions is that the definition is nor-


mally put in the header file and not in a cpp file. The actual rule is that any
declaration and definition should be in the same file. So if you are writing
a library function, the definition must be in the header file because that is
where the declaration has to be.
The reason for this rule is that the code for a template function is not fully
compiled until the template is actually used. It cannot be compiled until the

Armstrong, J 2016, C++ for Financial Mathematics, CRC Press, Boca Raton. Available from: ProQuest Ebook Central. [21 August 2017].
Created from uts on 2017-08-21 16:39:23.
An Overview of Templates 297

template is used because the types are not yet known. This means that users
of your library will need to have access to the code required to define all your
templated functions. This in turn means that these definitions need to be in
the header file.

Danger!

If you are writing a templated library function, the definitions and declarations
must be in the header files.

17.2 Template classes


The most visible use of template classes in C++ is in data types such as
vector<double>. The syntax for template classes is very similar to that used
for template functions.
Let us suppose we want to write a very simple data structure class called
SimpleVector, which stores a vector of a fixed size n and allows the user to
access the values at index i using functions set and get. We would also like
to be able to use the same class to store values of any type.
To do this we write the class in the usual way, except we use a template
parameter T as a placeholder for the type of data stored. Here is the code for
our SimpleVector class.
template ␣ < typename ␣T >
class ␣ SimpleVector ␣ {
public :
/* ␣ Constructor ␣ */
SimpleVector ( int ␣ size );
Copyright © 2016. CRC Press. All rights reserved.

/* ␣ Destructor ␣ */
~ SimpleVector () ␣ {
delete [] ␣ data ;
}
/* ␣ Access ␣ data ␣ */
T ␣ get ( int ␣ index ) ␣ {
return ␣ data [ index ];
}
/* ␣ Access ␣ data ␣ */
void ␣ set ( int ␣ index , ␣ T ␣ value ) ␣ {
data [ index ] ␣ = ␣ value ;
}

Armstrong, J 2016, C++ for Financial Mathematics, CRC Press, Boca Raton. Available from: ProQuest Ebook Central. [21 August 2017].
Created from uts on 2017-08-21 16:39:23.
298 C++ for Financial Mathematics

private :
T * ␣ data ;
/* ␣ Rule ␣ of ␣ three ␣ -␣ we ␣ make ␣ these ␣ private ␣ */
SimpleVector ( const ␣ SimpleVector & ␣ o );
SimpleVector & ␣ operator =( const ␣ SimpleVector & ␣ o );
};

We have provided inline implementations of all methods except the con-


structor of our SimpleVector.
As with template functions, all definitions should be provided alongside
the declarations in header files. Unfortunately you need to repeat the line
declaring the template parameters you are using for every function definition.
In addition you must include the template parameter in the qualifier of the
name for all the functions you define. For example, here is how we have defined
the constructor for SimpleVector.
template ␣ < typename ␣T >
SimpleVector <T >:: SimpleVector ( ␣ int ␣ size ␣ ) ␣ {
data ␣ = ␣ new ␣ T [ size ];
}

As demonstrated in the unit test below, we can now use SimpleVector to


store various different data types.
void ␣ testSimpleVector () ␣ {
SimpleVector < double > ␣ v1 (3);
v1 . set (1 , ␣ 2.0);
ASSERT ( v1 . get (1) ␣ == ␣ 2.0);

SimpleVector < int > ␣ v2 (3);


v2 . set (1 , ␣ 2);
ASSERT ( v2 . get (1) ␣ == ␣ 2);
Copyright © 2016. CRC Press. All rights reserved.

SimpleVector < string > ␣ v3 (3);


v3 . set (1 , ␣ " Test ␣ string " );
ASSERT ( v3 . get (1) ␣ == ␣ " Test ␣ string " );

It is possible to use multiple parameters in your templates. It is also pos-


sible to use certain simple data types such as constant integers as template
parameters. One example of this is the type array from the library <array>,
which is like a vector but of fixed length. When you create instances of array
you must specify both the type of the data and the length. Here is an example
of how you can use this type.
void ␣ testArray () ␣ {

Armstrong, J 2016, C++ for Financial Mathematics, CRC Press, Boca Raton. Available from: ProQuest Ebook Central. [21 August 2017].
Created from uts on 2017-08-21 16:39:23.
An Overview of Templates 299

array < int , ␣ 3 > ␣ a ;


a [2] ␣ = ␣ 1;
ASSERT ( a [2] ␣ == ␣ 1);
}

Tip: You Aren’t Going to Need It (YAGNI)

One of the slogans of extreme programming is “You Aren’t Going to Need


It”. Many programmers have a tendency to write the most general software
they possibly can. However, doing this can make your design more complex
and harder to use. Often the extra generality goes unused. There is clearly no
point writing code that will never be used.
You might be tempted to write a template version of our matrix class
so that we can store matrices of double, float or more usefully complex
numbers. However, the YAGNI slogan advises that you shouldn’t bother doing
this until you actually have a use for these classes.
In general, whenever you feel tempted to use templates, remember the
YAGNI slogan and ask yourself if it is really going to be worth the trouble
and complexity.

17.3 Templates as an alternative to interfaces


Recall that we introduced interface classes so that we could generalise our
Monte Carlo pricer, so that it can work equally well with any option. We can
solve this problem in a slightly different way using templates.
We can write a monteCarloPricer function that uses template to price
options of any class using any model so long as:
Copyright © 2016. CRC Press. All rights reserved.

(i) The option has a double valued field called maturity.

(ii) The option has a function payoff that takes the stock price at maturity
as a parameter and returns the payoff of that option.
(iii) The model has a function generateRiskNeutralPricePath that returns
a vector representing a simulated stock path in the risk-neutral measure.
This function must take as parameters: the time up to which we wish to
simulate the stock price path; the number of steps.
So long as all of these requirements are met, the following code will be able
to price the option using the given model.

Armstrong, J 2016, C++ for Financial Mathematics, CRC Press, Boca Raton. Available from: ProQuest Ebook Central. [21 August 2017].
Created from uts on 2017-08-21 16:39:23.
300 C++ for Financial Mathematics

template ␣ < typename ␣ Option , ␣ typename ␣ Model >


double ␣ monteCarloPrice (
const ␣ Option & ␣ option ,
const ␣ Model & ␣ model ,
int ␣ nScenarios ␣ = ␣ 10000) ␣ {
double ␣ total ␣ = ␣ 0.0;
for ␣ ( int ␣ i ␣ = ␣ 0; ␣i < nScenarios ; ␣ i ++) ␣ {
std :: vector < double > ␣ path ␣ = ␣ model .
generateRiskNeutralPricePath (
option . maturity ,
1);
double ␣ stockPrice ␣ = ␣ path . back ();
double ␣ payoff ␣ = ␣ option . payoff ( stockPrice );
total ␣ += ␣ payoff ;
}
double ␣ mean ␣ = ␣ total ␣ / ␣ nScenarios ;
double ␣ r ␣ = ␣ model . riskFreeRate ;
double ␣ T ␣ = ␣ option . maturity ␣ -␣ model . date ;
return ␣ exp ( - r * T )* mean ;
}
This code simply assumes that the actual classes representing the option and
the model obey all the requirements described above.
For example, the classes CallOption and BlackScholesModel meet these
requirements. So this test will compile and run.
void ␣ testMonteCarlo P r i c e r () ␣ {
CallOption ␣ c ;
c . strike ␣ = ␣ 110;
c . maturity ␣ = ␣ 1;
BlackScholesMod el ␣ model ;
model . stockPrice ␣ = ␣ 100;
Copyright © 2016. CRC Press. All rights reserved.

model . drift ␣ = ␣ 0;
model . riskFreeRate ␣ = ␣ 0.1;
model . volatility ␣ = ␣ 0.2;
model . date ␣ = ␣ 0;

double ␣ price ␣ = ␣ monteCarloPrice (c , ␣ model );


ASSERT_APPROX_EQ U A L ( price , ␣ c . price ( model ) , ␣ 0.1);
}
Note that the code will still run even if CallOption does not implement
any interfaces. What matters is the methods it has, not the interfaces it im-
plements. For example, BlackScholesModel doesn’t implement any particu-
lar interface, we’re just assuming that the model class passed to our template
function has a generateRiskNeutralPricePath method.

Armstrong, J 2016, C++ for Financial Mathematics, CRC Press, Boca Raton. Available from: ProQuest Ebook Central. [21 August 2017].
Created from uts on 2017-08-21 16:39:23.
An Overview of Templates 301

This solution may seem simpler than the solution we gave using polymor-
phism. However, it suffers from a number of significant problems.

• You need to write clear documentation of how to use your template


classes. In this documentation you will need to list all the functions
you expect to be present in your template parameter classes and their
return types. By contrast, an interface class automatically documents
this information. In addition the compiler checks that the interface is
correct.
• All the code must go in the header file. This makes encapsulation more
challenging and increases the coupling between your files. One practical
consequence of this is that your code will take longer to build.
• The compiler error messages that appear when you make a mistake with
templates are very confusing. In particular the compiler will often tell
you that the error is in a library file when it is in fact in your code. See
Exercise 17.3.1 for an example of this.
• When you use templates, the compiler only finds the errors when the
template is actually used. With object orientation, the errors are found
when the code is written.
Templates can work well in mature, stable, and carefully designed and
documented libraries such as the C++ standard library and Boost. They
are less effective in financial software that has to be constantly adapted to
changing business requirements.

Exercises
Copyright © 2016. CRC Press. All rights reserved.

17.3.1. Change the CallOption class in our template examples library so that
the word payoff is spelled incorrectly. Which file does the compiler say contains
the error?

17.3.2. Write a template class ComplexNumber which can be used to store


complex numbers of the form x + iy where x and y could both be doubles,
floats, or ints. The class should have a constructor which takes a single real
argument and a default constructor. It should be possible to add two complex
numbers with +.

17.3.3. Rewrite the integration example of Section 10.6 so that instead of


using polymorphism we use a template.

Armstrong, J 2016, C++ for Financial Mathematics, CRC Press, Boca Raton. Available from: ProQuest Ebook Central. [21 August 2017].
Created from uts on 2017-08-21 16:39:23.
302 C++ for Financial Mathematics

17.4 Summary
Templates provide a solution to the Once and Only Once principle that
is very useful for writing data structure classes. On the other hand, using
templates to write unnecessarily generic code violates the YAGNI principle
(You Aren’t Going to Need It).
Templates can be used as an alternative to virtual functions, but virtual
functions are normally the better approach.
For financial mathematics problems it is a good idea to take advantage of
library classes that are built using templates, but to avoid writing your own
template libraries.
Copyright © 2016. CRC Press. All rights reserved.

Armstrong, J 2016, C++ for Financial Mathematics, CRC Press, Boca Raton. Available from: ProQuest Ebook Central. [21 August 2017].
Created from uts on 2017-08-21 16:39:23.

Anda mungkin juga menyukai