| Share this page | Tweet |
Below the errata for the first printing of the book. These errata will be addressed in the second printing and the eBook version.
The full source code sent to registered readers was already correct and according to these errata, except for the errata for section 10.6 (example changed) and section 12.8 (wrong output) for code sent before 4 March 2011. Most errata provide extra information, add code that was missing from the book or address minor problems.
Errata last updated: 29 March 2012
When binding to the name we must use the greater<string> object
instead of greater<int>.
Thus the line:
boost::bind(greater<int>(), boost::bind(&Person::name, _1),
becomes:
boost::bind(greater<string>(), boost::bind(&Person::name, _1),
The code section defines the variable avg1 which is not further
used. To avoid confusion, the code section can be replaced by the
following:
// Create a vector with values
int size=4;
vector<double> v(size);
for (int i=0; i<size; ++i) v[i]=i*2.5;
// Finding the average with user-defined function object
// for_each returns the Average object so you can directly get the
result
// from it because Average implements the "cast to double" operator.
double avg = for_each(v.begin(), v.end(), Average());
cout << "Average: " << avg << endl;
// Multiply elements of a vector by a double using function object.
vector<double> v2(v);
for_each(v2.begin(), v2.end(),
MultiplyByValue<double>(2.0)); // Function object.
// Print the resulting vector.
cout<<"Vector multiplied by two: ";
for (int i = 0; i < v2.size(); ++i) cout<<v2[i]<<", "; cout<<endl;
The code section contain a for_ statement that accesses a
variable i that is defined outside the phoenix function. So at the
start of this code section, the following line must be added that defines i:
int i; // Space for the counter
When a Phoenix lambda fucntion get an object or object pointer as
argument, you might want to call a method on that object. However,
you can't directly use the dot (.) or arrow (->) operator on the
Phoenix variable. Instead you need to used the ->* operator with the
address of the member function to call. You use this on object
pointers. For objects you first need to take the address of the
variable:
// Call the Print() function on each shape.
// It is not possible to use the -> operator directly on a Phoenix
object pointer.
// So we need to use the ->* operator with the address of the
function to call.
// Not possible: for_each(vp.begin(), vp.end(), arg1->Print() );
for_each(vp.begin(), vp.end(), (arg1->*&Shape::Print)() );
// Call the Print function on all Point objects.
// Can't directly use the dot operator on a Phoenix object,
// but we can take the address of the object and then use the ->*
operator as with object pointers.
// Not possible: for_each(v.begin(), v.end(), arg1.Print() );
for_each(v.begin(), v.end(), (&arg1->*&Shape::Print)() );
Further you might need to down cast a base class pointer to a
derived class pointer. This is possible using the Phoenix
dynamic_cast_<T>() after which you can call a method on the derived
class using the ->* operator. Note that the ->* operator only works
for methods that are not overloaded:
// Cast the argument to a point and print X.
// We need the Phoenix
dynamic_cast_<>() to cast the Shape* to a Point*.
// Note, the ->* operator only works if the function is not
overloaded.
// So we need to use Point::GetX()/Point::SetX() instead of the
overloaded Point::X() getter/setter.
for_each(vp.begin(), vp.end(), cout<<val("x:
")<<((dynamic_cast_<Point*>(arg1))->*&Point::GetX)()<<endl );
When using the copy algorithm to copy to a list, you need the
back_inserter so the values are inserted at the end of the list. So
the line:
boost::phoenix::copy(arg1, arg2)(vA, myList);
becomes:
boost::phoenix::copy(arg1, arg2)(vA, back_inserter(myList));
The comment for assigning a shared pointer to a weak pointer is wrong. Thus the line:
// Assign weak pointer to shared pointer
becomes:
// Assign shared pointer to weak
pointer
The header files "nvp.hpp", "utility.hpp" and "version.hpp" are not essential for XML serialisation so their include statements can be removed.
The file is deserialised in the variable myMap which is not
defined. Thus before the line that creates the ifstream variable, add
the following line:
map<string, double> myMap;
The variable myTuple is defined twice. The second myTuple should
be renamed to myTuple2.
In the last code section, the opening, closing and delimeter
character for entering a tuple using cin, are changed to square
brackets and a comma. Thus the text displayed in the cout statement
must be changed from:
cout << "Enter a tuple in form (long double), e.g. [1, 2.2]: ";
to:
cout << "Enter a tuple in form [long, double], e.g. [1, 2.2]: ";
The implementation of the PropertyThing::operator = () function
is missing. It becomes:
PropertyThing<Name>& operator = (const PropertyThing<Name>&
source) { return *this; }
Figure 7.1 is the wrong one. Figure 7.1 should be:
Retrieving the wrong type from a variant will throw an exception. So the line that is commented out will compile but will throw an exception at run-time. It can be uncommented:
stA = boost::get<string>(myVariant); // Wrong type, throws
exception
The variant is initialized with a string but the comment says "default long". The comment should of course say "string"
variant<long, string> myFirst("Hello you all");
// Variant with string
The line:
complex<double> z4 = 2.0 + z4;
initializes z4 with 2.0 + z4 which leads to an undefined value.
Instead it should be initialized with 2.0 + z3. Thus it should read:
complex<double> z4 = 2.0 + z3;
Also the line:
complex<double> z8 = z2 * 2.0;
should be a division since the multiplication is already done for
z6. Thus it should read:
complex<double> z8 = z2 / 2.0;
The variable R8 was already defined in the previous code section.
Thus the variables in the last code section should be renamed:
rational<long> R9 = rational<long>(2, 5); // Classic
rational<long> R10;
R10.assign(2,5); // In-place assignment
The comment of the ToType() function reverses the input and
output. Instead of:
{ // Attempt to convert a T object to a string
it should read:
{ // Attempt to convert a string to a T object
The code part that makes trimmed copies of variable s1
has no effect
since s1 is already trimmed in the modifying trim functions
part above.
Thus the order of the modifying and trimmed copies parts should be
reversed.
The provide string to find matches in does not show the difference between first and last finders because there is only one match. The following changed code is a more clear example:
// First and last finders example
string str="the quick fox jumps over the lazy dog.";
cout<<"Source string: "<<str<<endl;
// The iterator range used for the result of the algorithms.
iterator_range<string::iterator> r;
// Find a range in an input string and then do something with it
r=find(str, first_finder("o", is_equal()) );
to_upper(r);
cout<<endl<<"First 'o' (case sensitive) converted to upper
case:"<<endl<<str<<endl;
r=find(str, last_finder("the", is_equal())
);
to_upper(r);
cout<<endl<<"Last 'the' (case sensitive) converted to upper
case:"<<endl<<str<<endl;
The function begin() is called on the variable myintersect (lower-case i) while the variable was declared as myIntersect (upper-case I). Thus the line:
set<double>::iterator i=myintersect.begin();
should become:
set<double>::iterator i=myIntersect.begin();
Two C-style strings can't be appended using the plus operator.
The should first be converted to an std::string type before adding.
Thus the lines:
string strB = "Field 1,Field 2 with \"embedded quote\",Field 3
Field 1," +
"Field 2 with \n new line,Field 3";
become:
string strB = string("Field 1,Field 2 with \"embedded quote\",")
+
string("Field 3 Field 1,Field 2 with \n new
line,Field 3");
The text claims that the output is on one line. But one of the fields tokenized contains a new line (\n) character. Thus the output is on two lines as follows:
Field 1 Field 2 with embedded quote Field 3 Field 1 Field 2
with
new line Field 3
The regular expresion variable rA is defined twice. These
variables should be renamed to rA1 and rA2.
Thus the lines:
regex rA("[1-5]*"); // Zero or more of any digit in
range [1..5]
regex rA("[^1-5]*"); // NOT in range([1..5])
become:
regex rA1("[1-5]*"); // Zero or more of any digit in
range [1..5]
regex rA2("[^1-5]*"); // NOT in range([1..5])
The regular expression to match different spellings of color/colour does not work with the spaces. So the spaces should be removed. The line:
regex myReg8("(Colo) (u) (r)",
boost::regex::icase|boost::regex::perl);
becomes:
regex myReg8("(Colo)(u)(r)",
boost::regex::icase|boost::regex::perl);
The variable tmp is not declared and is unneccessary. Thus the
lines:
tmp = atoi(value[1].str().c_str());
sum += tmp;
should replaced by:
sum += atoi(value[1].str().c_str());
In the example set refers to boost::expressive::set. Since this
can conflict with std::set because of the using namespace statements,
it should refer to set with the complete namespace. Thus
the line:
>> (delim= (set= '/','-')) // followed by a delimiter
becomes:
>> (delim= (boost::xpressive::set= '/','-')) // followed by a
delimiter
The code example uses constants NZ, NX and NY. These are
undefined and should be replaced by NDIM, NT and SIM respectively
who are defined earlier this section.
Thus the code becomes:
// Accessing elements using () with a collection of indices
typedef boost::array<Tensor::index, dim> Indices;
Indices indices;
for (indices[2]=0; indices[2] < NDIM; indices[2]++)
{
for (indices[0]=0; indices[0] < NT; indices[0]++)
{
for (indices[1]=0; indices[1] < NSIM; indices[1]++)
{
tensor(indices) = 0.0;
}
}
}
The fortran_storage_order object passed to the IntegerCube
constructor is missing the constructor brackets. Thus the line:
IntegerCube myFortranCube(extents[rows][columns][layers],
boost::fortran_storage_order);
becomes:
IntegerCube myFortranCube(extents[rows][columns][layers],
boost::fortran_storage_order());
Further in the code, there is a GeneralStorage object created
with the default constructor which is later used as argument when
constructing an IntegerCube by calling the () operator on the
GeneralStorage object. This does not compile.
The IntegerCube constructor should get a GeneralStorage object as
argument created with the ordering and ascending parameters. The line that created the GeneralStorage object can be removed
and later created when creating the IntegerCube object. The
code thus becomes:
// User-defined storage order
const int N = 3;
typedef boost::general_storage_order<N> GeneralStorage;
// last, then first, then second dimension
IntegerCube::size_type ordering[] = {2,0,1};
bool ascendingYN[] = {false, true, true};
IntegerCube myStoredCube(extents[rows][columns][layers],
GeneralStorage(ordering, ascendingYN));
Template arguments must be literals or constant variables. So the lines:
int NROWS = 3; int NCOLUMNS = 3;
Matrix<double, NROWs, NCOLUMNS> myMatrix;
must be:
const int NROWS = 3; const int NCOLUMNS = 3;
Matrix<double, NROWS, NCOLUMNS> myMatrix;
Also note the NROWS argument was misspelled with a lowercase 's' the 2nd
line.
The variable 'N' is defined as:
const long N = 2000;
The line declaring variable 'a' in the GaussianKernal()
function is missing. So add the following line at the beginning of
this function:
const double a = 1.0 / sqrt(2.0 * 3.1415);
The definitions of variables M, Lower, Upper, h and increment
were missing. So add the following lines at the start of the last
code section of the page:
// Calculate the bandwidth
long M = 60; // Number of mesh points in x direction
double Lower = -3.0;
double Upper = 3.0;
double h = (Upper - Lower) / M;
double increment = h;
The operator [] of the std::map being used in the print()
fucntion is non-const. Thus the sm input argument must be passed as
non-const. Thus the line:
template <int N> void print(const SparseMatrix<N>& sm)
becomes:
template <int N> void print(SparseMatrix<N>& sm)
The type MyHeapPointMgr was not defined. Before the main()
function there must be the following typedef:
typedef ObjectManager<HeapFactory<Point> > MyHeapPointMgr;
Directly calling the implementation() function on the derived
class does not show the use of the CRTP pattern. It should call the
interface() function of the base class that in its turn calls the
implementation() function of the derived class. Thus the lines:
Derived_A d1;
d1.implementation(); d1.static_func();
Derived_B d2;
d2.implementation(); d2.static_func();
become:
Derived_A d1;
d1.interface(); d1.static_func();
Derived_B d2;
d2.interface(); d2.static_func();
Class Base_A is the same as defined at the begining of the CRTP
section. Class Base_B is defined as:
template <typename Derived> struct Base_B
{
void calculate()
{
// ...
static_cast<Derived*>(this)->calculate();
// ...
}
};
Further, to use the CRTP pattern, the line calling
implementation() on the derived class must call the interface() base
class function instead. Thus the line:
d12.calculate(); d12.implementation(); d12.static_func();
becomes:
d12.calculate(); d12.interface(); d12.static_func();
Taking the absolute value of a square is unneccessary since a square is already positive. Thus the line:
result += fabs(vec[i] * vec[i]);
Could be rewritten as:
result += vec[i] * vec[i];
The serialize() function is split for the bus_stop_destination
class. The save() function should be const. Also when
loading, first the base class data should be loaded and then the
name member. Thus the code becomes:
// Separate save and load operations
template <class Archive>
void save(Archive& ar, const unsigned int version) const
{
ar & boost::serialization::base_object<bus_stop>(*this) & name;
}
template <class Archive>
void load(Archive& ar, const unsigned int version)
{
ar & boost::serialization::base_object<bus_stop>(*this);
if (version > 0)
{
ar & name;
}
}
BOOST_SERIALIZATION_SPLIT_MEMBER()
Finally the class version must be set for the bus_stop_destination
class:
// The current version
BOOST_CLASS_VERSION(bus_stop_destination, 1)
| Share this page | Tweet |