<<

. 7
( 9)



>>

fact that it could not be copied. We achieved this by making all the constructors
including the copy constructor private. Whilst a class will inevitably own its
own constructors, there is a way of implementing a general solution to the copying
problem. This will have the main virtue that a user of the class can immediately
see that it cannot be copied rather than having to be told by the compiler or by
inspecting to see whether a private copy constructor has been declared.
The key observation that makes this technique work is that if a class has a
private copy constructor or assignment operator, then any class inherited from
it cannot be copied or assigned either, since the inherited class implicitly holds a
base class object.
Here™s the important part of the relevant ¬le from Boost,
“boost/noncopyable.hpp”.

class noncopyable
{
protected:

197
198 Templatizing the factory

noncopyable() {}
˜noncopyable() {}
private: // emphasize the following members are private
noncopyable( const noncopyable& );
const noncopyable& operator=( const noncopyable& );
};
The class is very small and has no data members. Its constructor and destructor are
protected to ensure that it can only be constructed by an inherited class. The copy
constructor and assignment operator are, of course, private to ensure that even
inherited classes cannot make a copy.
To use this class we simply inherit our new class from it. For example, a typical
use would be
class MySingleton : private noncopyable
{

...

};
Note that here we have used private inheritance for the ¬rst time. Whereas
public inheritance express the “is a” relationship, private inheritance is said
to express “implemented in terms of a.” The main difference is that the inherited
class™s public interface does not contain the public part of the base class with
private inheritance. In our example, of course, the base class does not contain
any public methods, so the difference is purely in how we communicate our in-
tentions to clients of Singleton.
Note that private inheritance and object composition are very similar. Indeed,
if we had a data-member of type noncopyable (which is not possible unless we
modify the class to have a public constructor), then Singleton would not be
copyable either. However, the clear statement at the start of the class is more trans-
parent to users.
There is also a subtlety relating to object size. If we take sizeof a class with no
data members, what do we get? With good reason, the standard requires the number
to be greater than zero. Much code implicitly assumes that this is the case. For ex-
ample, suppose we created a vector of objects from a class with no data-members.
The implementer may well have decided to multiply and divide by sizeof when
working out an offset in memory; if zero size objects were allowed, this would
cause serious trouble.
So an object of type noncopyable has positive size. This means that having
a data member of its type will increase the size of an object; this is certainly a
14.3 The curiously recurring template pattern 199

disincentive to using this pattern. The reader is probably now saying, “ah but the
same applies to inheritance.” Generally, an object contains an instance of the base
class so inheriting off something simply adds to the size of the base class. However,
this is not true when the base class is empty. In that case, the standard allows the
compiler to optimize away the dummy space. So the private inheritance model has
no overhead and the virtue of clarity.


14.3 The curiously recurring template pattern
Now suppose we decide to implement a reusable singleton via inheritance. All
our singleton classes will inherit off a class called Singleton. We can inherit a
Singleton class off noncopyable and make the constructor private to ensure
that only methods of the class can create objects from it.
The trickier problem is how to implement the method that returns the sole in-
stance of the class. Our previous solution was to have a method that contained a
static data declaration of the class type. But the class does not know the type of
the inherited class “ information ¬‚ows downwards not upwards with inheritance.
One solution to this problem called the “curiously recurring template pattern” is
to templatize on the type of the inherited class. A little surprisingly, this is legal
C++. Our singleton therefore takes the form
template<class T>
class Singleton : private noncopyable
{
public:
static T& Instance()
{
static T one;
return one;
}

protected:
Singleton() {}

};
To create a new class which is a singleton class called MyFactory, we then code
class MyFactory : public Singleton<MyFactory>
{

...
200 Templatizing the factory

private:

...

MyFactory(){}
friend class Singleton<MyFactory>;

};

Note the friend declaration, the constructor for MyFactory is private so we need
this to allow the Singleton class to create the one object from MyFactory.


14.4 Using argument lists
Did you try Exercise 10.2? If not, think about it for a little while before continuing.
In fact, let™s consider a harder problem. Suppose we want to be able to specify
lots of different numbers of arguments of varying types. Our ¬rst exotic option
might require two arrays, a double, and three strings. Our second might require
one array, a boolean, a matrix, and one string. This could happen, and if we want
to implement a generic factory, then we have to cope not just with objects from the
same inheritance hierarchy requiring such varying arguments, but also with pieces
of code that have totally different requirements.
We could templatize on the argument type but would then still have the problem
of variable numbers of arguments. We would therefore have to have a template for
each possible number of arguments. This would be tiresome at best. An alternative
approach is to have one class that encapsulates all reasonable sorts of arguments.
Such a class is generally called an argument list. (There is a mechanism in C for
functions to have variable numbers of arguments, but this is rarely if ever used in
C++.)
We present such a class in ArgList.h from the xlw project. (For further discus-
sion of xlw see Chapter 15.)

Listing 14.1 (ArgList.h)

#ifndef ARG_LIST_H
#define ARG_LIST_H

#include <xlw/port.h>
#include "CellMatrix.h"
#include "MyContainers.h"
#include <map>
14.4 Using argument lists 201

#include <string>
#include <vector>

void MakeLowerCase(std::string& input);

class ArgumentList
{
public:

ArgumentList(CellMatrix cells,
std::string ErrorIdentifier);

ArgumentList(std::string name);


enum ArgumentType
{
string, number, vector, matrix,
boolean, list, cells
};

std::string GetStructureName() const;

const std::vector<std::pair<std::string, ArgumentType> >&
GetArgumentNamesAndTypes()
const;

std::string GetStringArgumentValue(
const std::string&
ArgumentName);

unsigned long GetULArgumentValue(
const std::string&
ArgumentName);

double GetDoubleArgumentValue(const std::string&
ArgumentName);

MyArray GetArrayArgumentValue(const std::string&
ArgumentName);
202 Templatizing the factory

MyMatrix GetMatrixArgumentValue(const std::string&
ArgumentName);

bool GetBoolArgumentValue(const std::string&
ArgumentName);

CellMatrix GetCellsArgumentValue(const std::string&
ArgumentName);

ArgumentList GetArgumentListArgumentValue(
const std::string&
ArgumentName);

// bool indicates whether the argument was found
bool GetIfPresent(const std::string& ArgumentName,
unsigned long& ArgumentValue);
bool GetIfPresent(const std::string& ArgumentName,
double& ArgumentValue);
bool GetIfPresent(const std::string& ArgumentName,
MyArray& ArgumentValue);
bool GetIfPresent(const std::string& ArgumentName,
MyMatrix& ArgumentValue);
bool GetIfPresent(const std::string& ArgumentName,
bool& ArgumentValue);
bool GetIfPresent(const std::string& ArgumentName,
CellMatrix& ArgumentValue);
bool GetIfPresent(const std::string& ArgumentName,
ArgumentList& ArgumentValue);

bool IsArgumentPresent(const std::string&
ArgumentName) const;
void CheckAllUsed(const std::string& ErrorId) const;
CellMatrix AllData() const;

// data insertions

void add(const std::string& ArgumentName,
const std::string& value);
void add(const std::string& ArgumentName,
double value);
14.4 Using argument lists 203

void add(const std::string& ArgumentName,
const MyArray& value);
void add(const std::string& ArgumentName,
const MyMatrix& value);
void add(const std::string& ArgumentName,
bool value);
void add(const std::string& ArgumentName,
const CellMatrix& values);

void add(const std::string& ArgumentName,
const ArgumentList& values);

void addList(const std::string& ArgumentName,
const CellMatrix& values);
private:

std::string StructureName;

std::vector<std::pair<std::string,
ArgumentType> > ArgumentNames;
std::map<std::string,double> DoubleArguments;
std::map<std::string,MyArray> ArrayArguments;
std::map<std::string,MyMatrix> MatrixArguments;
std::map<std::string,std::string> StringArguments;
std::map<std::string,CellMatrix> ListArguments;
std::map<std::string,CellMatrix> CellArguments;
std::map<std::string,bool> BoolArguments;
std::map<std::string,ArgumentType> Names;
std::map<std::string,bool> ArgumentsUsed;
void GenerateThrow(std::string message,
unsigned long row,
unsigned long column);

void UseArgumentName(const std::string& ArgumentName);
// private as no error checking performed

void RegisterName(const std::string& ArgumentName,
ArgumentType type);
};
#endif
204 Templatizing the factory

The class allows data from seven different types: string, number, vector, ma-
trix, boolean, list, and cells. An arbitrarily large amount of data from each of these
types is allowed. Data are retrieved by using a string as key. Most of these types
are self-explanatory, but we discuss the others. The type number is essentially
a double but could be interpreted in others ways, e.g. an int or an unsigned
long.
The type cells expresses the notion of a table of values that can be of multiple
types: string, number, boolean, error, or empty. The idea here is to abstract the no-
tion of values contained in cells in a spreadsheet, since ultimately xlw is a package
for interfacing C++ with Excel.
The type list says that the argument is an ArgList itself. This turns out to be
very useful. For example, suppose we wish to implement a random number gen-
erator factory with the arguments and type of generator speci¬ed via an ArgList.
Now suppose we want to do a class that does anti-thetic sampling of an arbitrary
generator. We make the constructor of the anti-thetic sampling decorator class (see
Chapter 6) take in an ArgList with an argument of type list called “InnerGen-
erator” and use this to create the object to be decorated.
The idea is that the user of a factory should pass in an argument list that contains
all the data necessary to identify the object to be created and to create it. These data
will vary from class to class both in amount and type. The argument list has a name
that expresses the base class type, e.g. “payoff,” rather than the speci¬c inherited
class. The factory will retrieve the identi¬er key by asking the argument list for a
string argument called “name.”
The argument list is then passed by the factory to the constructor for the inherited
class identi¬ed. It then queries the argument list for each piece of data it needs to
create the object. Often a constructor will have to deal with optional data, so the
argument list will have to provide facilities for checking if arguments are present
and also for obtaining a list of the arguments™ names and types. One big problem
that can arise with optional arguments is that the user misspells an optional name
and the constructor thinks it is not there, so we also have to introduce a mechanism
for checking that all arguments have been used.
The methods of the class are in a number of types. We include two constructors,
a few methods for retreiving general information, a large number of methods for
retreiving information of each type, and methods for adding information of each
type. We discuss these individually.
The method

std::string GetStructureName() const;

returns the type of the structure. This will always be in lower case, as will all
strings returned by the structure.
14.4 Using argument lists 205

The ability to get a complete list of all arguments by name and type is given by
const std::vector<std::pair<std::string, ArgumentType> >&
GetArgumentNamesAndTypes() const;
For each type we provide a method for retrieving arguments of that type. For ex-
ample, to get an argument we use
MyArray GetArrayArgumentValue(const std::string& ArgumentName);
The ArgumentName is turned into lower case before being matched to the list of
arguments. The ArgList class will throw an error if the argument requested is not
present.
Note that we provide two ways of retrieving arguments of type number
unsigned long GetULArgumentValue(
const std::string& ArgumentName);

double GetDoubleArgumentValue(
const std::string& ArgumentName);
The idea here is that, whilst the data passed in from a spreadsheet will not make
a distinction, it is sometimes convenient to have the data already cast to the right
type before use.
To cope with optional arguments, we include
bool GetIfPresent(const std::string& ArgumentName,
MyArray& ArgumentValue);
Note that these methods all have the same name, since the argument type is part of
the function signature. If the argument is present, ArgumentValue is overwritten,
otherwise it is left alone. The return value indicates whether the argument was
found.
We also include
bool IsArgumentPresent(const std::string& ArgumentName) const;
for testing whether an argument has been included.
To make sure no arguments have been accidentally ignored, we also include the
method
void CheckAllUsed(const std::string& ErrorId) const;
which throws if there is an unused argument and attaches the ErrorId to the error
message which also identi¬es the name of the unused argument. Clearly, we could
alternatively have this method return a bool and then decide what to do if there is
206 Templatizing the factory

an unused argument. The reason for simply having a throw is to avoid the necessity
of writing the same code saying to throw if there is an unused argument each time.
Note that the reason that the data retrieval mechanisms are non-const is that they
record whether an argument has been used.
We provide two ways of creating ArgumentLists
ArgumentList(std::string name);

ArgumentList(CellMatrix cells,
std::string ErrorIdentifier);
The ¬rst of these simply creates an empty object with nothing but a name. The
second is intended to be used when creating argument lists from a spreadsheet.
The user will put the data in a table of cells in the sheet, and pass this table to a
function. The function will then create an argument list from it; this list can then be
used to create objects from a factory. We defer further discussion of this constructor
to Section 14.8 where we discuss the CellMatrix class.
Clearly, an empty argument list is not much use so we have the ability to add
arguments using the add methods. These are pretty self-explanatory. Note that we
have an extra one addList which allows the addition of a list argument ex-
pressed by a CellMatrix instead of as an ArgumentList “ we discuss the reason
for this below.
An additional advantage of the add method is that when working with a function
in a spreadsheet, we often want to run many cases varying one parameter. We
can then use a CellMatrix, which describes all arguments except one, which is
inputted separately and varies from cell to cell. Note that both name and value
could be inputted independently allowing extra ¬‚exibility.
Our remaining public method is
CellMatrix AllData() const;
which converts the argument list into a CellMatrix, which can then be used to
construct the list again if so desired. This can be useful for returning large amounts
of data to a spreadsheet, or simply for checking whether the class is working cor-
rectly.


14.5 The private part of the ArgumentList class
How do we implement the ArgumentList class? We have a std::string that
represents the structure name as a data member. We have a data member for each
type which is implemented using the std::map class from the Standard Template
Library.
14.5 The private part of the ArgumentList class 207

This stores each data member together with its key. We store the key in lower
case and will convert any keys to lower case before querying the map. Note that
for all types except list the type stored in the map is the same as the type to be
returned.
For list, we store a CellMatrix instead. The reason for this is that the alter-
native is to have type ArgumentList as a template argument for a map which is a
data member of type ArgumentList. Whilst some compilers can cope with this,
some cannot. And coping is largely dependent on the particular implementation of
the standard library in use. So to avoid trouble we store lists as a CellMatrix;
since we have methods to convert to and from CellMatrix, this is easy.
Note that there would be an inef¬ciency here if the ArgumentList was being
queried repeatedly in a tight loop, but the class is not designed for ef¬ciency in
a numerical situation. Instead, it should be used for setting up objects before nu-
merical work starts, and returning data when it is ¬nished. Note that this is why
we have included a method addList for adding a CellMatrix describing a list;
this allows us to add a list without doing all these conversions.
We have two further maps. The data member
std::map<std::string,ArgumentType> Names;
stores all the names in a map to allow the retrieval of the type of each argument.
The data member
std::map<std::string,bool> ArgumentsUsed;
is initially set to have all bools false. Each time an argument is queried, we can
then set the relevant bool to true.
We have one more data member
std::vector<std::pair<std::string, ArgumentType> >
ArgumentNames;
This is simply used for storing all the names and types of arguments.
We also have three private methods. These are private since they are only to
be used internally by the class.
void GenerateThrow(std::string message,
unsigned long row,
unsigned long column);
is used by the constructor that takes in a CellMatrix. It throws a message that
identi¬es where the problem was in the inputted CellMatrix. This is to avoid
code duplication between methods.
The method
208 Templatizing the factory

void UseArgumentName(const std::string& ArgumentName);

is to set the relevant bool in the ArgumentsUsed map to true. Once again, we
use a method here to avoid duplication.
The method

void RegisterName(const std::string& ArgumentName,
ArgumentType type);

updates the ArgumentNames and ArgumentUsed. This will be used by each of the
add methods. It also checks that the same name has not been inserted twice.


14.6 The implementation of the ArgumentList
We present the source ¬le for the ArgumentList, excluding the parts for conver-
sion to and from CellMatrix, which we defer to Section 14.8.

Listing 14.2 (ArgList.cpp)

#include "ArgList.h"
#include <algorithm>
#include <sstream>

namespace
{
template<class T>
T maxi(T i, T j)
{
return i > j ? i : j;
}
}

void MakeLowerCase(std::string& input)
{
std::transform(input.begin(),input.end(),input.begin(),
tolower);
}

std::string ConvertToString(double Number)
{
std::ostringstream os;
os << Number;
14.6 The implementation of the ArgumentList 209

return os.str();

}

std::string ConvertToString(unsigned long Number)
{
std::ostringstream os;
os << Number;
return os.str();

}


void ArgumentList::add(const std::string& ArgumentName,
const std::string& value)
{
ArgumentType thisOne = string;
std::pair<std::string, ArgumentType> thisPair(ArgumentName,
thisOne);
ArgumentNames.push_back(thisPair);

std::pair<std::string,std::string> valuePair(ArgumentName,
value);
StringArguments.insert(valuePair);

RegisterName(ArgumentName, thisOne);
}

void ArgumentList::add(const std::string& ArgumentName,
double value)
{
ArgumentType thisOne = number;
std::pair<std::string, ArgumentType>
thisPair(ArgumentName,
thisOne);
ArgumentNames.push_back(thisPair);

std::pair<std::string,double> valuePair(ArgumentName,
value);
DoubleArguments.insert(valuePair);
210 Templatizing the factory

RegisterName(ArgumentName, thisOne);

}

void ArgumentList::add(const std::string& ArgumentName,
const MyArray& value)
{
ArgumentType thisOne = vector;
std::pair<std::string,
ArgumentType> thisPair(ArgumentName,thisOne);

ArgumentNames.push_back(thisPair);
ArrayArguments.insert(std::make_pair(ArgumentName,value));

RegisterName(ArgumentName, thisOne);
}

void ArgumentList::add(const std::string& ArgumentName,
const MyMatrix& value)
{
ArgumentType thisOne = matrix;
std::pair<std::string, ArgumentType>
thisPair(ArgumentName,
thisOne);

ArgumentNames.push_back(thisPair);
MatrixArguments.insert(std::make_pair(ArgumentName,
value));

RegisterName(ArgumentName, thisOne);
}
void ArgumentList::add(const std::string& ArgumentName,
bool value)
{
ArgumentType thisOne = boolean;
std::pair<std::string, ArgumentType>
thisPair(ArgumentName,
thisOne);

ArgumentNames.push_back(thisPair);
14.6 The implementation of the ArgumentList 211

BoolArguments.insert(std::make_pair(ArgumentName,value));

RegisterName(ArgumentName, thisOne);
}

void ArgumentList::add(const std::string& ArgumentName,
const CellMatrix& values)
{
ArgumentType thisOne = cells;
std::pair<std::string, ArgumentType>
thisPair(ArgumentName,
thisOne);

ArgumentNames.push_back(thisPair);
CellArguments.insert(std::make_pair(ArgumentName,
values));

RegisterName(ArgumentName, thisOne);

}


void ArgumentList::addList(const std::string& ArgumentName,
const CellMatrix& values)
{
ArgumentType thisOne = list;
std::pair<std::string, ArgumentType>
thisPair(ArgumentName,thisOne);
ArgumentNames.push_back(thisPair);
ListArguments.insert(std::make_pair(ArgumentName,values));

RegisterName(ArgumentName, thisOne);
}

void ArgumentList::add(const std::string& ArgumentName,
const ArgumentList& values)
{
CellMatrix cellValues(values.AllData());
addList(ArgumentName,cellValues);
}
212 Templatizing the factory

void ArgumentList::RegisterName(const std::string&
ArgumentName,ArgumentType type)
{
ArgumentNames.push_back(std::make_pair(ArgumentName,type));

if (!(Names.insert(*ArgumentNames.rbegin()).second) )
throw("Same argument name used twice"+ArgumentName);

ArgumentsUsed.insert(std::pair<std::string,bool>
(ArgumentName,false));
}

std::string ArgumentList::GetStructureName() const
{
return StructureName;
}

const std::vector<std::pair<std::string,
ArgumentList::ArgumentType> >&
ArgumentList::GetArgumentNamesAndTypes() const
{
return ArgumentNames;
}

void ArgumentList::UseArgumentName(const std::string&
ArgumentName)
{
std::map<std::string,bool>::iterator it=
ArgumentsUsed.find(ArgumentName);
it->second =true;
}

std::string ArgumentList::GetStringArgumentValue(const
std::string& ArgumentName_)
{
std::string ArgumentName(ArgumentName_);
MakeLowerCase(ArgumentName);
std::map<std::string, std::string>::const_iterator
it = StringArguments.find(ArgumentName);
14.6 The implementation of the ArgumentList 213

if (it == StringArguments.end())
throw(StructureName+std::string(" unknown string"
"argument asked for :")+ArgumentName);

UseArgumentName(ArgumentName);

return it->second;

}

unsigned long ArgumentList::GetULArgumentValue(const
std::string& ArgumentName_)
{
std::string ArgumentName(ArgumentName_);
MakeLowerCase(ArgumentName);
std::map<std::string, double>::const_iterator
it = DoubleArguments.find(ArgumentName);

if (it == DoubleArguments.end())
throw(StructureName+std::string(
" unknown unsigned long argument asked for :")
+ArgumentName);

UseArgumentName(ArgumentName);

return static_cast<unsigned long>(it->second);
}

double ArgumentList::GetDoubleArgumentValue(const
std::string& ArgumentName_)
{
std::string ArgumentName(ArgumentName_);
MakeLowerCase(ArgumentName);
std::map<std::string, double>::const_iterator
it = DoubleArguments.find(ArgumentName);

if (it == DoubleArguments.end())
throw(StructureName+std::string(
" unknown double argument asked for :")
+ArgumentName);
214 Templatizing the factory

UseArgumentName(ArgumentName);
return it->second;
}

MyArray ArgumentList::GetArrayArgumentValue(const
std::string& ArgumentName_)

{
std::string ArgumentName(ArgumentName_);
MakeLowerCase(ArgumentName);
std::map<std::string, MyArray>::const_iterator
it = ArrayArguments.find(ArgumentName);

if (it == ArrayArguments.end())
throw(StructureName+std::string(
" unknown array argument asked for :")
+ArgumentName);


UseArgumentName(ArgumentName);
return it->second;

}

MJMatrix ArgumentList::GetMatrixArgumentValue(const
std::string& ArgumentName_)
{

std::string ArgumentName(ArgumentName_);
MakeLowerCase(ArgumentName);
std::map<std::string, MJMatrix>::const_iterator
it = MatrixArguments.find(ArgumentName);

if (it == MatrixArguments.end())
throw(StructureName+std::string(
" unknown matrix argument asked for :")
+ArgumentName);

UseArgumentName(ArgumentName);
return it->second;
14.6 The implementation of the ArgumentList 215

}
bool ArgumentList::GetBoolArgumentValue(const
std::string& ArgumentName_)
{
std::string ArgumentName(ArgumentName_);
MakeLowerCase(ArgumentName);
std::map<std::string, bool>::const_iterator it =
BoolArguments.find(ArgumentName);

if (it == BoolArguments.end())
throw(StructureName+std::string(
" unknown bool argument asked for :")+ArgumentName);

UseArgumentName(ArgumentName);
return it->second;
}

ArgumentList ArgumentList::GetArgumentListArgumentValue(
const std::string& ArgumentName_)
{
std::string ArgumentName(ArgumentName_);
MakeLowerCase(ArgumentName);
std::map<std::string, CellMatrix>::const_iterator
it = ListArguments.find(ArgumentName);

if (it == ListArguments.end())
throw(StructureName+std::string(
" unknown ArgList argument asked for :")
+ArgumentName);
UseArgumentName(ArgumentName);
return ArgumentList(it->second,ArgumentName);
}

CellMatrix ArgumentList::GetCellsArgumentValue(
const std::string& ArgumentName_)
{
std::string ArgumentName(ArgumentName_);
MakeLowerCase(ArgumentName);
std::map<std::string, CellMatrix>::const_iterator
it = CellArguments.find(ArgumentName);
216 Templatizing the factory

if (it == CellArguments.end())
throw(StructureName+std::string(
" unknown Cells argument asked for :")+ArgumentName);

UseArgumentName(ArgumentName);
return it->second;
}

bool ArgumentList::IsArgumentPresent(
const std::string& ArgumentName_) const
{
std::string ArgumentName(ArgumentName_);
MakeLowerCase(ArgumentName);
return (Names.find(ArgumentName) != Names.end());
}

void ArgumentList::CheckAllUsed(
const std::string& ErrorId) const
{
std::string unusedList;

for (std::map<std::string,bool>::const_iterator it
= ArgumentsUsed.begin(); it != ArgumentsUsed.end(); it++)
{
if (!it->second)
unusedList+=it->first + std::string(", ");
}

if (unusedList !="")
throw("Unused arguments in "+ErrorId+" "+StructureName
+" "+unusedList);

}

void ArgumentList::GenerateThrow(std::string message,
unsigned long row,
unsigned long column)
{
throw(StructureName
+" "+message
14.6 The implementation of the ArgumentList 217

+" row:"
+ConvertToString(row)
+"; column:"+ConvertToString(column)+".");
}

ArgumentList::ArgumentList(std::string name)
: StructureName(name)
{

}

bool ArgumentList::GetIfPresent(
const std::string& ArgumentName,
unsigned long& ArgumentValue)
{
if (!IsArgumentPresent(ArgumentName))
return false;

ArgumentValue = GetULArgumentValue(ArgumentName);
return true;
}

bool ArgumentList::GetIfPresent(
const std::string& ArgumentName,
double& ArgumentValue)
{
if (!IsArgumentPresent(ArgumentName))
return false;
ArgumentValue = GetDoubleArgumentValue(ArgumentName);
return true;
}

bool ArgumentList::GetIfPresent(
const std::string& ArgumentName,
MyArray& ArgumentValue)
{
if (!IsArgumentPresent(ArgumentName))
return false;

ArgumentValue = GetArrayArgumentValue(ArgumentName);
218 Templatizing the factory

return true;
}

bool ArgumentList::GetIfPresent(
const std::string& ArgumentName,
MyMatrix& ArgumentValue)
{
if (!IsArgumentPresent(ArgumentName))
return false;

ArgumentValue = GetMatrixArgumentValue(ArgumentName);
return true;
}

bool ArgumentList::GetIfPresent(
const std::string& ArgumentName,
bool& ArgumentValue)
{
if (!IsArgumentPresent(ArgumentName))
return false;

ArgumentValue = GetBoolArgumentValue(ArgumentName);
return true;
}

bool ArgumentList::GetIfPresent(
const std::string& ArgumentName,
CellMatrix& ArgumentValue)
{
if (!IsArgumentPresent(ArgumentName))
return false;

ArgumentValue = GetCellsArgumentValue(ArgumentName);
return true;
}

bool ArgumentList::GetIfPresent(
const std::string& ArgumentName,
ArgumentList& ArgumentValue)
{
14.6 The implementation of the ArgumentList 219

if (!IsArgumentPresent(ArgumentName))
return false;

ArgumentValue = GetArgumentListArgumentValue(ArgumentName);
return true;
}
We start with a simple implementation of the maximum function: maxi. Note
that the correct thing to do here is actually use the std::max function from the
standard template library; however, some implementations “forgot” to include it
(notably Visual Studio 6.0), so in the interests of cross-platform compatibility, we
use an alternative.
We have three functions for manipulating strings.
void MakeLowerCase(std::string& input);
simply takes a string and using the tolower function from the C Standard Li-
brary, converts its elements to lower case. Note the use of the transform algo-
rithm from the standard template library which is neater than looping through the
elements of the string.
The two ConvertToString functions take in numbers and spit out strings.
This is acheived by using the sstream class. This works similarly to iostreams.
The difference being that the objective is to create a string rather than an in-out
buffer. We include these functions since they will be useful when creating error
messages that say that a certain element of a CellMatrix is incorrect, which is
very useful when debugging spreadsheets.
We have an add method for each argument type. Almost all of these do the same
things: add the argument name and type to ArgumentNames, insert the name and
value into the map for this argument type, and call RegisterName. The method
addList takes the same form.
The one add method that is different is the one for adding lists. This converts
the input ArgumentList into a CellMatrix and calls the addList method, thus
avoiding the issue of having ArgumentList data members.
The “get” methods are also very similar to each other. For each one, we copy the
input string, convert it to lower case, and look up the map to see if it is present. If
it is not present, we throw, and if it is, we store the fact that it has been used, and
return the value.
Once again it is the list method that has an additional step. Here we get
a CellMatrix from the map and convert it to an ArgumentList on ¬nal re-
turn. A subtlety worth mentioning is that with the current design, it is only at
this point that the CellMatrix is checked for validity. So if the CellMatrix
contains errors, then a throw will occur. Note that we could create a dummy
220 Templatizing the factory

variable of type ArgumentList to be discarded in the addList method from the
CellMatrix in order to check the argument™s validity at the time of addition to the
object.
We also include the GetIfPresent methods to make it easy for the user to
deal with optional arguments. These simply test if the argument is present and
if it is, overwrite the parameter passed by value. A bool is returned indicating
if the argument was found. These were included to save the user from having to
repeatedly write code to test if an argument were present and then do one thing it
it was and another if it was not.
The remaining methods are self-explanatory and we do not comment on the
implementation further.


14.7 Cell matrices
Suppose we are interfacing a function with EXCEL or another spreadsheet. The
most general form of input will be a table of values from the sheet. The ob-
ject of the CellMatrix is to abstractize this concept. We can use this class as
a facade between the spreadsheet™s internal data types and our numerical code™s
objects.
The class is presented in <xlw/CellMatrix.h>

Listing 14.3 (CellMatrix.h)
#ifndef CELL_MATRIX_H
#define CELL_MATRIX_H

#include <xlw/port.h>
#include <string>
#include <vector>
#include <xlw/MyContainers.h>

class CellValue
{

public:
bool IsAString() const;
bool IsANumber() const;
bool IsBoolean() const;
bool IsError() const;
bool IsEmpty() const;
14.7 Cell matrices 221

CellValue(const std::string&);
CellValue(double Number);
CellValue(unsigned long Code, bool Error);
//Error = true if you want an error code

CellValue(bool TrueFalse);
CellValue(const char* values);
CellValue(int i);


CellValue();

const std::string& StringValue() const;
double NumericValue() const;
bool BooleanValue() const;
unsigned long ErrorValue() const;

std::string StringValueLowerCase() const;

enum ValueType
{
string, number, boolean, error, empty
};

operator std::string() const;
operator bool() const;
operator double() const;
operator unsigned long() const;

void clear();
private:
ValueType Type;
std::string ValueAsString;
double ValueAsNumeric;
bool ValueAsBool;
unsigned long ValueAsErrorCode;
};

class CellMatrix
{
222 Templatizing the factory

public:

CellMatrix(unsigned long rows, unsigned long columns);
CellMatrix();
CellMatrix(double x);
CellMatrix(std::string x);
CellMatrix(const char* x);
CellMatrix(const MyArray& data);
CellMatrix(const MyMatrix& data);
CellMatrix(unsigned long i);
CellMatrix(int i);

const CellValue& operator()(
unsigned long i, unsigned long j) const;
CellValue& operator()(unsigned long i, unsigned long j);

unsigned long RowsInStructure() const;
unsigned long ColumnsInStructure() const;

void PushBottom(const CellMatrix& newRows);

private:

std::vector<std::vector<CellValue> > Cells;
unsigned long Rows;
unsigned long Columns;
};
CellMatrix MergeCellMatrices(const CellMatrix& Top,
const CellMatrix& Bottom);
#endif

The implementation of the class is largely as a table of objects of type CellValue.
We therefore discuss the CellValue class ¬rst. This is intended to represent the
possible values a cell can hold. Thus we have 5 types of values:

enum ValueType
{
string, number, boolean, error, empty
};
14.7 Cell matrices 223

giving the possibilities of it holding a string, a double, a bool, an error code,
or simply being empty. The error codes are represented by unsigned longs, in
accordance with the practice in EXCEL.
The methods
bool IsAString() const;
bool IsANumber() const;
bool IsBoolean() const;
bool IsError() const;
bool IsEmpty() const;
allow us to test if a CellValue is of a given type. Once we know it is of that type,
then we can get it via the methods
const std::string& StringValue() const;
double NumericValue() const;
bool BooleanValue() const;
unsigned long ErrorValue() const;
std::string StringValueLowerCase() const;
with the obvious effects. Note that a CellValue can be of at most one type and
attempting to use it as another will yield a throw.
Note that we also have the methods
operator std::string() const;
operator bool() const;
operator double() const;
operator unsigned long() const;
which may appear a little confusing to the reader. These are implicit conversion
operators. For example, suppose a routine, f, expects a double and we have a
CellValue called x holding a double. We can use our original methods to code
f(x.NumericValue());
but it would be nice if we could just put
f(x);
Implicit conversion operators allow us to do this. The declaration
operator double() const;
says that the CellValue can be treated as a double and, when this is done, the
method
224 Templatizing the factory

CellValue::operator double() const

is called to give the requisite value. Note that with conversion to user-de¬ned
classes an alternative is simply to write a new constructor that takes in a
CellValue, but this is not an option for inbuilt types such as doubles.
We also provide constructors for various types to make it easy to create
CellValues. In addition, we provide a method for clearing the value: clear().
The implementation of this class is straightforward and the details can be found
in the ¬le CellMatrix.cpp in the xlw project.
The CellMatrix class itself is just a table of values implemented as a vector of
vectors for simplicity. Note that using a vector of vectors is not recommended
for numerical code for ef¬ciency reasons “ it may result in data in the same matrix
being in rather different parts of the memory and switching memory locations is
time consuming. Here, however, we are purely interested in convenience and the
design is adequate.
The main thing to remark on in the class is the number of constructors. This
is because we will want to write functions returning lots of different types to the
spreadsheet. By making the CellMatrix constructors take in all of these, we can
simply write routines that return them and convert to a CellMatrix automatically
and via that to a spreadsheet data-type. Otherwise the user will be perpetually writ-
ing code at the end of routines to convert data to the correct type.
Note we include a couple of routines for merging CellMatrix objects.
PushBottom simply adds some new rows to the bottom of the CellMatrix, widen-
ing the object if necessary. MergeCellMatrices does essentially the same thing
but with a non-member function interface.
The implementation of this class is straightforward and can be found in
CellMatrix.cpp.


14.8 Cells and the ArgumentLists
We now return to our discussion of the ArgumentList, and in particular look at its
methods relating to cells. The most important of these is the constructor that takes
in a CellMatrix

ArgumentList(CellMatrix cells,
std::string ErrorIdentifier);

The idea is that the user in a spreadsheet enters a table of values and these are
then used to construct an argument list, which can then be used to create on object
from the factory. The constructor takes in an additional string to make it easy to
identify where the problem occurred in the event of an error being thrown.
14.8 Cells and the ArgumentLists 225

The constructor uses an auxiliary routine ExtractCells. The implementation
is fairly straightforward and we only comment on the unusual parts.

CellMatrix ExtractCells(CellMatrix& cells,
unsigned long row,
unsigned long column,
std::string ErrorId,
std::string thisName,
bool nonNumeric)
{
if (!cells(row,column).IsANumber())
throw(ErrorId+" "+thisName+
"rows and columns expected.");
if (cells.ColumnsInStructure() <= column+1)
throw(ErrorId+" "+thisName+
"rows and columns expected.");
if (!cells(row,column+1).IsANumber())
throw(ErrorId+" "+thisName+
"rows and columns expected.");

unsigned long numberRows = cells(row,column);
unsigned long numberColumns = cells(row,column+1);

cells(row,column).clear();
cells(row,column+1).clear();

CellMatrix result(numberRows,numberColumns);

if (numberRows +row+1>cells.RowsInStructure())
throw(ErrorId+" "+thisName+
"insufficient rows in structure");

if (numberColumns +column>cells.ColumnsInStructure())
throw(ErrorId+" "+thisName+
"insufficient columns in structure");

for (unsigned long i=0; i < numberRows; i++)
for (unsigned long j=0; j < numberColumns; j++)
{
result(i,j) = cells(row+1+i,column+j);
226 Templatizing the factory

cells(row+1+i,column+j).clear();

if (!result(i,j).IsANumber())
nonNumeric = true;
}


return result;


}


ArgumentList::ArgumentList(CellMatrix cells,
std::string ErrorId)
{
CellValue empty;
unsigned long rows = cells.RowsInStructure();
unsigned long columns = cells.ColumnsInStructure();

if (rows == 0)
throw(std::string(
"Argument List requires non empty cell matix")
+ErrorId);

if (!cells(0,0).IsAString())
throw(
std::string("a structure name must be specified"
"for argument list class ")+ErrorId);
else
{
StructureName = cells(0,0).StringValueLowerCase();
cells(0,0) = empty;
}
{for (unsigned long i=1; i < columns; i++)
if (!cells(0,i).IsEmpty() )
throw("An argument list should only"
"have the structure name"
"on the first line: "
+StructureName+ " " + ErrorId);
14.8 Cells and the ArgumentLists 227

}

ErrorId +=" "+StructureName;
{for (unsigned long i=1; i < rows; i++)
for (unsigned long j=0; j < columns; j++)
if (cells(i,j).IsError())
GenerateThrow("Error Cell passed in ",i,j);}


unsigned long row=1UL;

while (row < rows)
{
unsigned long rowsDown=1;
unsigned column = 0;

while (column < columns)
{
if (cells(row,column).IsEmpty())
{
// check nothing else in row
while (column< columns)
{
if (!cells(row,column).IsEmpty())
GenerateThrow("data or value where"
" unexpected."
,row, column);
++column;
}
}
else // we have data
{
if (!cells(row,column).IsAString())
GenerateThrow(
"data where name expected.",
row, column);

std::string thisName(
cells(row,
column).StringValueLowerCase());
228 Templatizing the factory

if (thisName =="")
GenerateThrow(
"empty name not permissible.",
row, column);

if (rows == row+1)
GenerateThrow("No space where data"
"expected below name",
row, column);

cells(row,column).clear();
// weird syntax to satisfy VC6
CellValue* belowPtr = &cells(row+1,column);
CellValue& cellBelow = *belowPtr;

if (cellBelow.IsEmpty())
GenerateThrow(
"Data expected below name",
row, column);

if (cellBelow.IsANumber())
{
add(thisName, cellBelow.NumericValue());
column++;
cellBelow=empty;
}
else
if (cellBelow.IsBoolean())
{
add(thisName,
cellBelow.BooleanValue());
column++;
cellBelow=empty;
}
else // ok its a string
{
std::string stringVal
= cellBelow.
StringValueLowerCase();
14.8 Cells and the ArgumentLists 229

if ( (cellBelow.StringValueLowerCase()
== "list") ||
(cellBelow.StringValueLowerCase()
== "matrix") ||
(cellBelow.StringValueLowerCase()
== "cells") )
{
bool nonNumeric = false;
CellMatrix extracted(
ExtractCells(cells,
row+2,
column,
ErrorId,
thisName,
nonNumeric));


if (cellBelow.StringValueLowerCase()
== "list")
{
ArgumentList value(extracted,
ErrorId+":"
+thisName);

addList(thisName,
extracted);
//note not value

}

if (cellBelow.StringValueLowerCase()
== "cells")
{
add(thisName,extracted);
}


if (cellBelow.StringValueLowerCase()
== "matrix")
{
230 Templatizing the factory

if (nonNumeric)
throw("Non numerical value"
" in matrix argument :"
+thisName+ " "+ErrorId);

MJMatrix value(
extracted.RowsInStructure(),
extracted.ColumnsInStructure());

for (unsigned long i=0;
i < extracted.
RowsInStructure(); i++)
for (unsigned long j=0;
j < extracted.
ColumnsInStructure(); j++)
ChangingElement(value,i,j) =
extracted(i,j);
add(thisName,value);

}

cellBelow = empty;
rowsDown = maxi(rowsDown,
extracted.RowsInStructure()+2);
column+= extracted.
ColumnsInStructure();
}
else // ok its an array or boring string
{
if (cellBelow.StringValueLowerCase()
== "array"
|| cellBelow.StringValueLowerCase()
== "vector" )
{
cellBelow.clear();

if (row+2>= rows)
throw(ErrorId
+" data expected below"
"array "+thisName);
14.8 Cells and the ArgumentLists 231

unsigned long size =
cells(row+2,column);
cells(row+2,column).clear();

if (row+2+size>=rows)
throw(ErrorId
+" more data expected"
"below array"+thisName);




MyArray theArray(size);

for (unsigned long i=0; i < size;

<<

. 7
( 9)



>>