Modern C++ Design Errata

The list below is created by readers and C++ users like you and maintained by the book's author.

To add entries, please contact Andrei. Don't forget to specify the printing, which can be seen at the bottom of the copyright page (the one just before Contents) and reads like "First printing, May 2001".

Page

Print Current text Correction Submitter
0 1-16

Second code snippet:

typedef SingletonHolder<
    A, StaticAllocator, MyCreator> SingleA;

typedef SingletonHolder SingleA;

 

Manuel Menezes de Sequeira
6 1-16

Furthermore, for class templates ***with multiple parameters*** you can use partial specialization (as you will see in Chapter 2).
[This sentence suggests that using multiple parameters enables you to use PTS, which is not quite true, since template <class T> class X is also PTS.]

Furthermore, for class templates ***[erased]*** you can use partial special­ization (as you will see in Chapter 2).

Grzegorz Jakacki
7 1-16

Comment reads:

// Error! Cannot partially specialize a
// member class of Gadget

[Author's note: The comment has been formatted to two lines from one to better fit this column.]

change "class" to "function" 

Derek Chen-Becker
7 1-16


// OK: specialization of a member function of Widget

template<> Widget::Fun()


// OK: specialization of a member function of Widget

template<> void Widget::Fun() 

Sumit Rajan
12 1-16

For this reason, the user can automatically convert a host ***class*** to a policy and later delete ***that pointer.***

For this reason, the user can automatically convert a host ***class pointer*** to a policy ***pointer*** and later delete  ***the host class object through this pointer.***

Grzegorz Jakacki
14 1-16

template
<
  class T,
  template class CheckingPolicy,
  template class ThreadinModel
>
  class SmartPtr;

template
<
  class T,
  template class CheckingPolicy,
  template class ThreadinModel
>
  class SmartPtr; 

James Turetsky
14 1-16

please remove my "correction"

 

James Turetsky
15 1-16

By plugging in various checking policy classes, you can implement various behaviors. You can even initialize the ***pointee object*** with a default value by accepting a reference to a pointer, as shown:

By plugging in various checking policy classes, you can implement various behaviors. You can even initialize the ***pointer*** with a default value by accepting a reference to a pointer, as shown: 

Grzegorz Jakacki
16 1-16

The last sentence (really line of code) on page 16 (which contains an error), and the first two "sentences" on page 17 (for context only) read:

    void SetPointer(PointerType ptr) { pointee_ = ptr; }
private:
    PointerType ptr_;

The last sentence (really line of code) on page 16 should read:

    void SetPointer(PointerType ptr)
    { ptr_ = ptr; }


I.e. there is no pointee_ data member in this class, but in the previous class... 

David Brownstein
16 1-16

Consequently, Structure should expose types called PointerType (***the type of the pointed-to object***) and ReferenceType (***the type to which the pointer refers***) and functions such as GetPointer and SetPointer.

Consequently, Structure should expose types called PointerType (***the type of a pointer to the pointed-to object***) and ReferenceType (***the type of a reference to the pointed-to object***) and functions such as GetPointer and SetPointer.

 

Grzegorz Jakacki
18 1-16

The 3rd sentence on page 18 reads:
template <class> class CP1,

should read:
template <class> class CP1
(extra comma is not allowed here) 

reported by Tatsuya Watanabe (submitted by M.Murakami)
18 1-16

In the second text paragraph, it says:
and a NoChecking with a SmartPtrExtended-
.
with line break as shown. There are two problems: < character in the wrong place and confusing hyphenation.

Change to:
and a NoChecking with a SmartPtr.
Also, fix justification of the paragraph so that ExtendedWidget is not split across a line break. 

Guy Middleton
18 1-16

In the second text paragraph, ExtendedWidget is misspelled.

Change ExtendedWiget to ExtendedWidget

Guy Middleton
18 1-16

The code at the top of page 18 will not compile on any compiler I am familiar with if pointee_ is of type T* as this code implies.  The problem, is that one cannot access privates of a class that's not the same type as itself.  In the templated copy c'tor, the other object is not of the same type as this.  So, how could this possibly have access to the other's privates?

IOW, given the code on page 18, SmartPtr<int> cannot access the privates of SmartPtr<double> because, once the compiler generates the code from the templates, they are two distinct types.  There is no built-in friendship between classes generated from the same template.

The solution, as is applicable in many situations like these is to introduce another level of "indirection" through another class.  For example, if one were to implement the pointee_ member of SmartPtr as a class type, preferably templated, such as the Storage policy mentioned on page 17, one could implement accessor operators on the Storage policy type that could allow one to assign a storage policy object containing one type to another storage policy containing another type.  And then, one would not find one's compiler complaining at oneself. ;-) 

Trey Nash
18 1-16

18  
[reported by Tatsuya Watanabe (submitted by M.Murakami)] The 3rd sentence on page 18 reads:
template class CP1,

The problem is with the 3rd line, not sentence. 

Joe Bloggs
19 1-16

(actually on page xix; but the form does not accept roman page numbers)

http://www.modernpcdesign.com

http://www.moderncppdesign.com/ 

Ingolf Steinbach
25 1-16

The version of STATIC_CHECK included near the center of the page is invalid.  The expression sizeof(Compile­Time­Checker<(expr)>( ERROR_##msg())) is an invalid attempt to take the size of a function declaration.

[Author's note: Many readers have submitted this bug. The simplest solution is to simply add extra parens around ERROR_##msg() (solution 1 below). The actual Loki code looks like solution 2 below:]


// solution 1
#define STATIC_CHECK(expr, msg) \
    {\
        class ERROR_##msg {}; \
        (void)sizeof(::Loki::CompileTimeChecker<\
            (expr) != 0>((ERROR_##msg())));\
    }

// solution 2
#define STATIC_CHECK(expr, msg) \
    { Loki::CompileTimeError<((expr) != 0)> \
    ERROR_##msg; \
    (void)ERROR_##msg; }


Many thanks to Greg Underwood, Carl Daniel and others who noticed the bug and proposed changes.] 

Many
25 1-16

typo: ::Loki::CompilerTimeChecker<\

::Loki::CompileTimeChecker<\ 

Thomas Schell
25 1-16

The sizeof operand is still a function type.

// solution 1
#define STATIC_CHECK(expr, msg) \
    {\
        class ERROR_##msg {}; \
        (void)sizeof(::Loki::CompileTimeChecker<\
            (expr) != 0>((ERROR_##msg())));\
    }

// solution 1
#define STATIC_CHECK(expr, msg) \
    {\
        class ERROR_##msg {}; \
        (void)sizeof((::Loki::CompileTimeChecker<\
            (expr) != 0>(ERROR_##msg())));\
    }

Fraser Ross
25 1-16


Useless brackets and != 0 expressions.

#define STATIC_CHECK(expr) \
         CompileTimeError()


// solution 1
#define STATIC_CHECK(expr, msg) \
    { \
        class ERROR_##msg {}; \
        (void)sizeof((::Loki::CompileTimeChecker \
            (ERROR_##msg()))); \
    }

 

Fraser Ross
25 1-16

(expr) != 0

(expr) != 0 is needed for some smart pointers. 

Fraser Ross
26 1-16

Finally, sizeof gauges the size of the resulting ***temporary variable.***

Finally, sizeof gauges the size of the resulting ***temporary value.***

 

Grzegorz Jakacki
26 1-16


(void)sizeof(
     CompileTimeChecker<(sizeof(From) <= sizeof(To))>(
             ERROR_Destination_Type_Too_Narrow()));

(void)sizeof((
     CompileTimeChecker(
             ERROR_Destination_Type_Too_Narrow())));

In text remove brackets:

Fraser Ross
30 1-16 pSomeObj is defined by pObj is used replace pSomeObj with pObj Daniel Feist
31 1-16

Int2Type comes in very handy as a means to translate a value into a type. You then pass a ***temporary variable*** of that type to an overloaded function.

Int2Type comes in very handy as a means to translate a value into a type. You then pass a ***temporary value*** of that type to an overloaded function.

Grzegorz Jakacki
36 1-16

To test inheritance the conversion class will not be usable with supposed base classes for which copying is prevented by a copy ctor declared private but without implementation.

Change static Small Test(U); to static Small Test( const U& );  

Chris Theis
37 1-16


#define SUPERSUBCLASS_STRICT(T, U) \
    (SUPERSUBCLASS(T, U) && \
    !::Loki::Conversion<const T, const U>::sameType)


#define SUPERSUBCLASS_STRICT(T, U) \
    (SUPERSUBCLASS(T, U) && \
    !::Loki::Conversion<const T*, const U*>::sameType)

 

Tim Ford
37 1-16

The typeid operator returns a reference to a type_info object:
[...]
The typeid operator returns a reference to an object of type type_info.

Remove second occurence. 

Grzegorz Jakacki
39 1-16

comment in 2nd source code reads:
... pBase actually points to a Derived object ...

should be:
... pObj actually points to a Derived object ...

 

reported by Hiroaki Itoh (submitted by M.Murakami)
40 1-16

Missing return in the Copy function template.

Insert line return result; before }

Milivoj Davidov
41 1-16

In the second code segment:
iterIsPtr ? "fast" : "smart" << '\n';

(iterIsPtr ? "fast" : "smart") << '\n'; 

Boris Pulatov
41 1-16

On page 41 and the following pages where the TypeTraits class is described:

template <typename T>
class TypeTraits
{
    // ...
public:
    typedef PointerTraits::PointeeType
        PointeeType;
    typedef Select             || isMemberPointer, T, ReferredType&>::Result
        ParameterType;
    typedef UnConst::Result NonConstType;
    // ...
};

There are some typenames missing and should look like this:

template <typename T>
class TypeTraits
{
    // ...
public:
    typedef typename PointerTraits::PointeeType
        PointeeType;
    typedef typename Select             || isMemberPointer, T, ReferredType&>::Result
        ParameterType;
    typedef typename UnConst::Result NonConstType;
    // ...
};

 

Sebastian Ramacher
41 1-16

The following code does not compile with g++ v3.4.3 due to implications of C++98 standard. The compiler options used are -Wall and -std=c++98.


class NullType {};
template <typename T>
class TypeTraits
{
    private:
        template <class U> struct PointerTraits
        {
            enum { result = false };
            typedef NullType PointeeType;
        };
        template <class U> struct PointerTraits
        {
            enum { result = true };
            typedef U PointeeType;
        };

    public:
        enum { isPointer = PointerTraits::result };
        typedef typename PointerTraits::PointeeType PointeeType;
};

However, following reorganization helps:


class NullType {};
template <class U> struct PointerTraits
{
    enum { result = false };
    typedef NullType PointeeType;
};
template <class U> struct PointerTraits
{
    enum { result = true };
    typedef U PointeeType;
};
template <typename T>
class TypeTraits
{
    private:


    public:
        enum { isPointer = PointerTraits::result };
        typedef typename PointerTraits::PointeeType PointeeType;
};

 

Joginder Singh
42 1-16

The definition of the part of TypeTraits dedicated to primitive types follows.

Replace "primitive" with "fundamental" (throughout the chapter).

 

Grzegorz Jakacki
42 1-16

TL::IndexOf     TYPELIST_nn(comma-separated list of types)
    >::value


..on page 43 also.

Should be replaced with:

TL::IndexOf<
    TYPELIST_nn(comma-separated list of types),
    T>::value


..as declared on page 56. 

Lars Rune Nøstdal
43 1-16

enum { isStdFundamental =
    isStdArith
    || isStdFloat
    || Conversionvoid>::sameType };

enum { isStdFundamental =
    isStdArith
    || Conversionvoid>::sameType };


isStdFloat is already included in isStdArith

Lars Rune Nøstdal
44 1-16

"[...] you still need to modify the pointer to Widget you hold internally."

This is not clear. Should it be "the pointer to const Widget"?  In that case one can modify the pointer (not the pointer const Widged), so there is no need to strip the const.

see erratum. 

Manuel Menezes de Sequeira
45 1-16

return CopyImpl(first, last, result, Int2Type);

return CopyImpl(first, last, result, Int2Type()); 

Boris Pulatov
45 1-16

BitBlast is very likely to produce an incorrect result when copying between an array of floats and an array of integers.  Still if the float type and the integer type have the same size, both Copy functions on page 45 and 46 will (indirectly) call BitBlast!

For an example, see CopyIntegersToFloats.cpp at

An extra line to both page 45 and 46 will fix the problem:


    TypeTraits::isStdFloat ==
        TypeTraits::isStdFloat &&


Place this line on both pages, just before the line that begins with:


    sizeof(SrcPointee) == sizeof(DestPointee)


 

Niels Dekker
45 1-16

(for 9th printing, Feb 2004 - it's not on the printing list)

The template Copy treats the fundamental types incorrectly.
It does not differentiate between the integer and floating point types.
For example, on Intel both int and float consist of 4 bytes,
so the template would happily BitBlast the byte representation
of ints into floats or vise versa.

Check separately for integer and float values.
But even that may be not enough in case if there
are multiple possible representation of ints or floats
of the same length. 

Sergey Babkin
46 1-16

There are two unrelated errors on this line:

return CopyImpl(first, last, Int2Type);

return CopyImpl(first, last, result, Int2Type());

 

Boris Pulatov
46 1-16

Both Copy functions on page 45 and 46 always select the conservative copy implementation if the InIt type is a pointer-to-const.  This is because
TypeTraits::isStdFundamental fails for any const type.  I tried MSVC++ 7.1 and GNU C++ 3.3.1.  See CopyConst.cpp at

Use TypeTraits::NonConstType to strip off the const-ness from both SrcPointee on page 45 and T on page 46.

 

Niels Dekker
46 1-16

In general, it is unsafe to do bitwise copying between different types of POD arrays, even if both POD types have the same size.  Still one might have specialized Supports­Bitwise­Copy for both POD types, just to allow bitwise copying between arrays of one and the same POD type.  And unfortunately, this would trigger the Copy function template on page 46 to select the bitwise BitBlast copy implementation.

For an example, see CopyPlainOldData.cpp at

I would suggest the following fix of Copy:


template <typename InIt, typename OutIt>
OutIt Copy(InIt first, InIt last, OutIt result,
    Int2Type<true>)
{
    typedef typename TypeTraits<
            typename TypeTraits
            ::PointeeType>::UnqualifiedType
        SrcPointee;
    typedef typename TypeTraits<
            typename typeTraits
            ::PointeeType>::UnqualifiedType
        DestPointee;

    enum { useBitBlast =
        TypeTraits::isPointer &&
        TypeTraits::isPointer &&
        SupportsBitwiseCopy::result &&
        SupportsBitwiseCopy::result &&
        Conversion::sameType ||
        (
            TypeTraits::isStdFundamental &&
            TypeTraits::isStdFundamental &&
            TypeTraits::isStdFloat ==
                TypeTraits::isStdFloat &&
            sizeof(SrcPointee) == sizeof(DestPointee)
        ) };
    return CopyImpl(first, last, result,
        Int2Type());
}

 

Niels Dekker
46 1-16

enum { result = TypeTraits::NonConstType };

code sample copied from Niels Dekker:

typedef typename TypeTraits::NonConstType NonConstType;

enum { result = TypeTraits::isStdFundamental };
 

Thomas Schell
46 1-16

useBitBlast should have assigned "Conservative" and "Fast" instead of bool

enum { useBitBlast = ... ? Fast : Conservative }; 

Thomas Schell
47 1-16

The type that's most appropriate as a parameter of a ***nonmutable*** function.

The type that's most appropriate as a parameter of a ***non-mutating*** function.

 

Grzegorz Jakacki
49 1-16

First bullet: Understanding ...

Understand 

Manuel Menezes de Sequeira
52 1-16

Second line from top of page, "vectordouble>>" should have a space between last pair of right angle brackets.

Change
  ...<double>>
to
  ...<double> >

Tom Browder
53 1-16

The implementation of Length uses partial template specialization (see Chapter 2) to distinguish between ***a null type and a typelist.***

The implementation of Length uses partial template specialization (see Chapter 2) to distinguish between ***NullType and a non-empty typelist.***

Grzegorz Jakacki
55 1-16

The generalized callback implementation decribed in Chapter 5 uses TypeAt-NonStrict.

The generalized callback implementation decribed in Chapter 5 uses TypeAtNonStrict

Grzegorz Jakacki
55 1-16



template <class Head, class Tail> struct TypeAt;


template <class TList, unsigned int index> struct TypeAt;
template <class Head, class Tail> 

Tom Titchener
57 1-16

if TList is non-null, then

The pseudo code should say "if TList is a Typelist, then" but its inconsistent with the pseudo code on other pages so the words could be removed. 

Fraser Ross
60 1-16

In algorithm Replace, last Else:

Else Result is a typelist with TList::Head as its head and the result of applying Replace to TList, T, and U as its tail.

Else Result is a typelist with TList::Head as its head and the result of applying Replace to TList::Tail, T, and U as its tail. 

Renato Cadoso Mesquita
62 1-16

The algorithm and code for DerivedToFront are wrong.  I verified this by writing a small test program that output the sequence of type names produced by DerivedToFront.

See
http://www.cs.ndsu.nodak.edu/~kvanhorn/Fall2002/GP/Lesson10/index.html
under "Partially Ordering Typelists".
[Author's note: The current Loki codebase in sourceforge has fixed this bug. On page 62, instead of "...L as its tail" please read "...DerivedToFront::Result as its tail"] 

Kevin S. Van Horn
62 1-16

Find the most derived type from TList::Head in TList::Tail. ***Store it in a temporary variable TheMostDerived.***

Find the most derived type from TList::Head in TList::Tail. ***Save that type via a typedef to a type called TheMostDerived..***

Grzegorz Jakacki
63 1-16

line 9
Apply MostDerived to TList::Tail and Base.

line 9

Apply MostDerived to TList::Tail and T

Andrea Bugin
65 1-16

The first specialization of GenScatterHierarchy only applies to typelists of length 2:

template <class T1, class T2,
    template <class> class Unit>
class GenScatterHierarchy<
        TYPELIST_2(T1, T2), Unit>
    : public GenScatterHierarchy
    , public GenScatterHierarchy
{
};

template <class Head, class Tail,
    template <class> class Unit>
class GenScatterHierarchy, Unit>
    : public GenScatterHierarchy
    , public GenScatterHierarchy
{
};


Fortunately, this bug is already fixed in the current Loki release, though I prefer the more descriptive names "Head" and "Tail" for the template parameters. 

Ernesto García García
65 1-16

Second template specialization of GenScatterHierarchy is listed as:


// Pass an atomic type (non-typelist) to Unit
template <class AtomicType, template<class> class Unit>
class GenScatterHierarchy : public Unit
{
  typedef Unit LeftBase;
};



Don't we have to specify the template parameters after GenScatterHierarchy for partial template specialization?


// Pass an atomic type (non-typelist) to Unit
template <class AtomicType, template<class> class Unit>
class GenScatterHierarchy : public Unit
{
  typedef Unit LeftBase;
};

 

Kei Takahashi
67 1-16

First code section:


WidgetInfo obj;
string name = (static_cast&>(obj)).value_;

The static_cast should be to Holder& to match the example. 

Mark Heaps
69 1-16

This happens because field N in a typelist is field N - 1 in the tail of that typelist, for any ***nonzero*** N.

This happens because field N in a typelist is field N - 1 in the tail of that typelist, for any ***positive*** N. 

Grzegorz Jakacki
71 1-16

EventHandler's destructor has returen type (void)

   virtual void ~EventHandler() {}
should be
   virtual ~EventHandler() {}

Junggon Kim
74 1-16

line 6
MyEventHandler

line 6
WidgetEventHandler 

Andrea Bugin
76 1-16


Null
Type

NullType 

Fraser Ross
77 1-16

The beginning of the chapter says:
This chapter discusses the design and that of implementation...

This chapter discusses the design and the implementation...

(should be "the" instead "that of") 

Shmulik Flint
80 1-16

Finally, SmallObject wraps FixedAllocator to offer encapsulated allocation services for C++ classes. SmallObject overloads operator new and operator delete and passes ***them*** to a SmallObjAllocator object.

Finally, SmallObject wraps FixedAllocator to offer encapsulated allocation services for C++ classes. SmallObject overloads operator new and operator delete and passes ***the allocation/deallocation requests*** to a SmallObjAllocator object.

Grzegorz Jakacki
82 1-16

First line: and Release releases the allocated memory
First bullet: unsignedshort

There is no Release method.  Should there be a destructor?
unsigned short 

Manuel Menezes de Sequeira
82 1-16

Don't forget we are at the very bottom here--everything matters. Again for efficiency reasons, Chunk does not define constructors, ***destructors***, or assignment operator.

Don't forget we are at the very bottom here--everything matters. Again for efficiency reasons, Chunk does not define constructors, ***destructor***, or assignment operator.

Grzegorz Jakacki
83 1-16

Number of elided blocks in Figures 4.4 and 4.5 should be 251, not 253

Change size of elided list to 251 

lorne schachter
84 1-16

The assignment operator for FixedAllocator does not implement reference linking correctly.  It is in the Loki Sourceforge version that can be downloaded.  The code is not specifically mentioned in the book.


FixedAllocator& FixedAllocator::operator=(
    const FixedAllocator& rhs )
{
  if ( this == &rhs ) {
    return *this;
  }

  // Check that the object being assigned is the only reference
  // to itself.  We can destroy it as long as no memory has been
  // allocated.  If there exists allocated blocks though, then we have
  // a memory leak, since the only reference (this) is being assigned
  // to another FixedAllocator.
  if ( prev_ == this && next_ == this )
  {
    Chunks::iterator i = chunks_.begin();
    for (; i != chunks_.end(); ++i)
    {
      // This checks if you have an allocated block in a
      // this FixedAllocator which is only referenced by 'this'.
      assert( i->blocksAvailable_ == numBlocks_ );
    }
  }

  // The copy semantics for reference linking imply that rhs will be
  // linked with this object, but we also have to remove the current
  // reference that this object may have with another FixedAllocator.
  // The way this is handled is that a copy surrogate is made which adds
  // another link into the rhs reference linking.  Then the data is
  // swapped, not the reference linking pointers, between the copy
  // and this object.  After the data is swapped, the 'this' object
  // is removed from its reference linking chain and added to the
  // rhs reference linking chain.  When copy goes out of scope and
  // since it is always linked to an existing FixedAllocator from
  // the copy constructor, when it dies, it simply removes the link.

  FixedAllocator copy( rhs );
  copy.Swap( *this );

  // removing the this object from the previous reference chain
  next_->prev_ = prev_;
  prev_->next_ = next_;

  // putting the this object into the rhs reference chain
  prev_ = &rhs;
  next_ = rhs.next_;
  rhs.next_->prev_ = this;
  rhs.next_ = this;

  return *this;
}
 

John Dill
85 1-16

When we have free block we have to move it to the end chunks_, otherwise we will have inefficient memory management.
Here is the problematic code:


if (lastChunk.blocksAvailable_ == numBlocks_)
{
    // Two free blocks, discard one
    lastChunk.Release();
    chunks_.pop_back();
    allocChunk_ = deallocChunk_;
}


[Author's note: This code is actually not in the book. The errata refers to the actual Loki source code, and has been fixed.]


if (lastChunk.blocksAvailable_ == numBlocks_)
{
    // Two free blocks, discard one
    lastChunk.Release();
    chunks_.pop_back();
    // move the empty chunk to the
    //end
    std::swap(*deallocChunk_, lastChunk);
    allocChunk_ = deallocChunk_;
}

 

Tomer Laor
89 1-16

Second paragraph: "... and a pointer to the last FixedDeallocator used for deallocation."

Should be FixedAllocator; there is no FixedDeallocator

Boris Pulatov
91 1-16

Singleton<...>

SingletonHolder<...> 

Jacques Bouchard
92 1-16

template <template <class T> class ThreadingModel>
void* SmallObject::operator new(
    std::size_t size)
{
   Lock lock;
   return MyAlloc::Instance().Allocate(size);
}

template <template <class T> class ThreadingModel>
void SmallObject::operator delete(
    void* p, std::size_t size)
{
   Lock lock;
   return MyAlloc::Instance().Deallocate(size);
}

template <template <class T> class ThreadingModel>
void* SmallObject::operator new(
    std::size_t size)
{
   typename ThreadingModel::Lock
       lock;
   return MyAlloc::Instance().Allocate(size);
}

template <template <class T> class ThreadingModel>
void SmallObject::operator delete(
    void* p, std::size_t size)
{
   typename ThreadingModel::Lock
       lock;
   return MyAlloc::Instance().Deallocate(size);
}

 

Ben Hutchings
100 1-16

10th printing has a misprint:

...call to the Con-
crete-
Command object

No need for a line break after Concrete-

...call to the Con-
creteCommand object 

James Turetsky
104 1-16

We could have simply said, "***Types*** that support operator() are callable entities."

We could have simply said, "***Objects of types*** that support operator() are callable entities."

Grzegorz Jakacki
107 1-16

we define a FunctorImpl explicit specialization

we define a FunctorImpl partial specialization 

Manuel Menezes de Sequeira
108 1-16

Impl is not a declared type before its use in this line:

explicit Functor(std::auto_ptr spImpl);

Insert class before the use of Impl:

explicit Functor(std::auto_ptr<class Impl> spImpl); 

Fraser Ross
110 1-16

Fifth line of first code segment including comments:

// operator()(double, int) is generated.

 

Should be

// operator()(int, double) is generated.

 

Boris Pulatov
111 1-16

The last line of the page:

The template stands for ...

And it should be:

The template stands for ... 

Georg Teichtmeister
111 1-16

The last example of this page is:


template <typename R, class TList>
template <typename Fun>
Functor::Functor(const Fun& fun)
  : spImpl_(new FunctorHandler(fun));
{
}



I believe that the semicolon before the function body is not needed.


template <typename R, class TList>
template <typename Fun>
Functor::Functor(const Fun& fun)
  : spImpl_(new FunctorHandler(fun))
{
}

 

Kei Takahashi
113 1-16

Consequently, the type of fun_ in FunctorHandler is void (&)(int, double) as well. When you invoke FunctorHandler<...>::operator(), it forwards to fun_(), which is legal syntax for invoking a function through a pointer to function.

Here fun_  is a *reference* to function. Replace pointer with reference. 

Grzegorz Jakacki
114 1-16

Third line (code) is missing the init-declarator:
Functor<void,TYPELIST_2(int, double)>

Change to read:
Functor<void,TYPELIST_2(int, double)> cmd1(pF); 

Rob Stewart
114 1-16

In the first code segment, in Method 2:
Functor<void, int, double> cmd2(

Functor<void, TYPELIST_2(int, double)> cmd2( 

Shmulik Flint
116 1-16

...&Parrot::eat;

...&Parrot::Eat; 

Alec Ross
119 1-16

Example code: No result type template parameter specified for the Functor class template (in function main() which tests Loki::MemFunHandler using the Parrot class, after the line "// Define two Functors"):
Functor<>

Functor<void> 

Milivoj Davidov
119 1-16

a new constructor for the Functor class is missing.

A constructor needs to be added to the Functor class that accepts object and pointer to member function (similiar to the constructor for regular functors in page 110), so main() can be compiled. (such a constructor exists in Loki) 

Shmulik Flint
120 1-16

Functor<void, int>

Functor<void, TYPELIST_1(int)> 

Jacques Bouchard
120 1-16

code at the end Incoming::Argument

Incoming::ParamList 

Andrea Bugin
120 1-16

The incoming Functor type is passed as the ***ParentFunctor*** parameter.

The incoming Functor type is passed as the ***Incoming*** parameter.

Grzegorz Jakacki
121 1-16

cout << Fun ...

cout << "Fun ... 

Alec Ross
121 1-16

In code:
... new BinderFirst(fun, bound)));
Fctr should be a typo of Fctor

Change Fctr to Fctor 

lostmouse
121 1-16

In the middle block of code, the private in the Outgoing typedef is wrong.

Change private to Private:


typedef typename
   Private::BinderFirstTraits...

 

Rob Stewart
122 1-16

Incorrect Loki class name - FunctorChain - specified within the text (once in the third paragraph, twice in the fourth just after the Loki code excerpt).

Replace FunctorChain with Chainer

Milivoj Davidov
124 1-16

source code near the bottom of page 124 reads:
class ThreadingModel = DEFAULT_THREADING,

should be:
class ThreadingModel = DEFAULT_THREADING
(extra comma is not allowed here) 

reported by Hiroaki Itoh (submitted by M.Murakami)
124 1-16

First paragraph of 5.13: Wrong font in "is copied"

See erratum. 

Manuel Menezes de Sequeira
125 1-16


std::auto_ptr pImpl_;
Missing the closing ">" for the auto_ptr template.


std::auto_ptr<
        FunctorImpl >
    pImpl_;
 

Scott Neugroschl
125 1-16

std::auto_ptr         R, TL ThreadingModel>
pImpl_;

Aside from the missing closing closing ">" reported by Scott Neugroschl, there is a missing comma between TL and ThreadingModel.

Consolidating the two:

std::auto_ptr<
        FunctorImpl >
    pImpl_;

 

Andrei Alexandrescu
132 1-16

Page 132, row 9, 6th word: dynamically

statically
[Author's note: Nope. This errata is pending deletion. Statically initialized objects are guaranteed to be initialized before the program starts. The sentence is referring to namespace-level objects (be they static or not) that are initialized dynamically.] 

Peter Nikolaev Koniarov
132 1-16

... "instance_ is initialized dynamically (...), whereas pInstance_ benefits from static initialization (...)." ...

... "pInstance_ is initialized dynamically (...), whereas instance_ benefits from static initialization (...)." ... 

Frank Pecher
133 1-16

The 1st source code on page 133 reads: Singleton& Instance();

should be: static Singleton& Instance(); 

reported by Hiroaki Itoh (submitted by M.Murakami)
133 1-16

Section 6.3 explains what need to be done in order to enforce the singleton uniqueness. It doesn't mention anything about making the address-of operator private.
But section 6-11 indicates that users of SingletonHolder should make adress-of operator private.

Explain if and why address-of operator of Singleton class should be made private. 

Shmulik Flint
136 1-16

Missing static in front of: Singleton& Instance();

Add static 

Jacques Bouchard
136 1-16

return pInstance_;

return *pInstance_; 

Jacques Bouchard
136 1-16

The class Singleton example code on page 136 and 137 has at least three problems:
1) 4th "sentence" on page 137 reads: Singleton pInstance_;
2) The Singleton class is missing a private constructor!
3) The destructor is in the private scope of the class- this makes the DTOR unreachable by any invoking code.
The MSVC compiler, for example, will complain: "Error C2248: Singleton::~Singleton(): cannot access private member Singleton::pInstance_ declared in class Singleton."
4) This is somewhat of a "style" comment: The boolean member destroyed_ is unnecessary.

1) It should read:  Singleton* pInstance_;
2) Add a private constructor to the class.
3) Move the destructor for the class into the public scope.
4) Dead reference detection could be performed simply by checking pInstance_ for NULL.
[Author's note: (1) is correct. (2) is not because the final line of Singleton says ... disabled tors/operator= ... which assumes the disabled stuff goes there. (3) is correct. (4) is subtle. The member destroyed_ is necessary because otherwise the code can't make a difference between a Singleton that was never created and a Singleton than was created once and then destroyed.] 

David Brownstein
136 1-16

static void Create();
{
    ...

static void Create()
{
    ...

 

Boris Pulatov
137 1-16

Singleton pInstance_;

static Singleton* pInstance_; 

Jacques Bouchard
137 1-16

The 5th line on page 137 reads:

bool destroyed_;

static bool destroyed_;

 

reported by Hiroaki Itoh (submitted by M.Murakami)
137 1-16

source code near the bottom of page 137 reads:
void KillPhoenixSingleton(); // Added

static void KillPhoenixSingleton(); // Added 

reported by Hiroaki Itoh (submitted by M.Murakami)
138 1-16


void Singleton::KillPhoenixSingleton()
{
    ...
    // It will set pInstance_ to zero ...
    ...
}



... "The destructor resets the pointer to zero" ...

You probably have to remove the code from section 6.5, p. 136, which sets pInstance_ to 0 on destruction, or the placement new operator will execute the constructor on address 0;
additionally, pInstance_ may not be set to 0 in KillPhoenixSingleton, or subsequent "ressurections" may fail. 

Frank Pecher
138 1-16

In function OnDeadReference you call Create() . It looks like it causes undefined behavior. Point 3.6.3/2 says:

"If a function contains a local object of static storage duration that has been destroyed and the function is
called during the destruction of an object with static storage duration, the program has undefined behavior."

The whole idea of 6.6 is questionable. 

Michal Rotkiewicz
140 1-16

About SetLongevity (twice): takes a reference

takes a pointer 

Manuel Menezes de Sequeira
140 1-16

When the application exits, all objects registered with SetLongevity are deleted in decreasing order of their longevity.

When the application exits, all objects registered with SetLongevity are deleted in INCREASING order of their longevity. 

Andrea Bugin
140 1-16

In other words, in this case we need Log to have a longer lifetime than Keyboard and Display.

[The relation between lengths of Log's and Keyboard's lifetimes says nothing about the order in which they die.]

In other words, in this case we need Log to die after Keyboard and Display.

Grzegorz Jakacki
140 1-16

Assuming the singleton does not provide a public constructor (following the book examples) the code below will not work.
SetLongevity(&SomeSingleton().Instance(), 5);

SetLongevity(&SomeSingleton::Instance(), 5); 

Leandro Melo
140 1-16


Log a longer life time

pDynObject will

Log a later death

pDynObject's object will 

Fraser Ross
142 1-16

Wrong comparison in LifetimeTracker::Compare

replace > with <
[Author's note: This bug has been fixed in the Loki library on sourceforge.] 

Jacques Bouchard
142 1-16

In turn, SetLongevity calls atexit, always passing it the same pointer to a function. This function pops one element off the ***stack*** and deletes it.

In turn, SetLongevity calls atexit, always passing it the same pointer to a function. This function pops one element off the ***priority queue*** and deletes it.

Grzegorz Jakacki
143 1-16

In code section: Deleter and ConcreteLifetimeTracker should live in namespace Private

At the begining of the code section, add:

namespace Private
{

and at the end (on next page), add the corresponding

}

 

lostmouse
143 1-16

In the text after the trackerArray definition:
There is only one instance of the Tracker type. No Tracker type was defined. The text must have meant TrackerArray.

There is only one instance of the TrackerArray type. 

Shmulik Flint
143 1-16

Last line: :LifetimeTracker(longevity),
the comma should be deleted

:LifetimeTracker(longevity) 

Rob Stewart
143 1-16

This being said, SetLongevity's implementation is simple: It creates a concrete tracker object, adds it to the ***stack***, and registers a call to atexit.

This being said, SetLongevity's implementation is simple: It creates a concrete tracker object, adds it to the ***priority queue***, and registers a call to atexit.
[and generally other similar fixes in chapter 6] 

Grzegorz Jakacki
144 1-16

Pages 144 and 145
In calls to realloc, the number of elements should be multiplied by sizeof(LifetimeTracker*)

See erratum.
[Author's note: This bug has been fixed in the Loki codebase on sourceforge.] 

Manuel Menezes de Sequeira
144 1-16

line 12 from the end: pTrackerQueue

pTrackerArray 

Andrea Bugin
145 1-16

SetLongevity(*this, longevity_);

SetLongevity(pInstance_, longevity_); 

Jonas Meyer Rasmussen
145 1-16

The code conveniently hides the data structures and AtExitFn in the Private namespace.

The code conveniently hides the data structures and AtExitFn in the Private namespace. (notice the font change) 

Grzegorz Jakacki
147 1-16

source code near the bottom of page 147 reads:

Guard myGuard(lock_); // 3

should be (to keep consistent with text):

Lock myGuard(mutex_); // 3



 

reported by Hiroaki Itoh (submitted by M.Murakami)
149 1-16

sections 6.10.1 and 6.10.4 introduce the concept of a singleton with infinite lifetime ("leaking", NoDestroy), but no previous discussion explains what is the reasoning of such Lifetime policy

Add a discussion in section 6.4 to explain when a "leaking" singleton might be useful. 

Shmulik Flint
150 1-16

The pInstance_ member of the SingletonHolder is defined as

   static InstanceType* pInstance_;

Later (on page 151) the double-checked locking pattern is applied to check pInstance_:

if (!pInstance_) {
   .....::Lock guard;
   if (!pInstance_) {
      ...
   }
}

(reformatted for brevity).

The compiler might decide that guard cannot have any influence on pInstance_ and optimize away the second check.

pInstance_ itself should be volatile:

   static InstanceType*volatile pInstance_;

 

Ingolf Steinbach
150 1-16

Still present in 15th printing:
typedef ThreadingModel::VolatileType InstanceType;
Missing typename keyword.

typedef typename ThreadingModel::VolatileType InstanceType; 

Daniel Sodja
151 1-16

near bottom of page:

LifetimePolicy::ScheduleCall( &DestroySingleton);

should be:

LifetimePolicy::ScheduleDestruction( &DestroySingleton);

 

Darren Ranalli
151 1-16

template<...> T& SingletonHolder<...>::Instance()
{
   ....
   return *pInstance_;
}

template<...> T& SingletonHolder<...>::Instance()
{
   ....
   return const_cast(*pInstance_);
}

Or maybe make Instance() return SingletonHolder<...>::InstanceType& rather than T&. (Don't forget to make InstanceType public. 

Ingolf Steinbach
154 1-16

0  
[Manuel Menezes de Sequeira] Second code snippet:

typedef SingletonHolder<
    A, StaticAllocator, MyCreator> SingleA;

The fix appears to be for P154. 

Joe Bloggs
155 1-16

Example reads:

typedef SingletonHolder     SingletonWithLongevity> Keyboard;
typedef SingletonHolder     SingletonWithLongevity> Display;
typedef SingletonHolder     SingletonWithLongevity> Log;

There is a parameter missing in the typedefs.
SingletonWithLongevity is a Lifetime-Policy but the second template parameter of SingletonHolder should be a Creation-Policy.
Thus the example should be something like this:

typedef SingletonHolder     SingletonWithLongevity> Keyboard;
typedef SingletonHolder     SingletonWithLongevity> Display;
typedef SingletonHolder     SingletonWithLongevity> Log;

 

Benjamin Kaufmann
156 1-16

Example reads:

typedef Singleton

 

typedef SingletonHolder

 

reported by Yusuke SATO (submitted by M.Murakami)
156 1-16

second line reads:
...by combining the other four parameters

change "four" to "three" 

lostmouse
158 1-16

Fifth line of first code segment:

explicit SmartPtr(T* pointee) : pointee_(pointee);

explicit SmartPtr(T* pointee) : pointee_(pointee) {...}


or

explicit SmartPtr(T* pointee);

 

Boris Pulatov
159 1-16

An object with value semantics is an object that you can copy and assign to. ***Type int*** is the perfect example of a first-class object.

An object with value semantics is an object that you can copy and assign to. ***A plain int*** is the perfect example of a first-class object.

Grzegorz Jakacki
160 1-16

the 3rd line from bottom of this page,
Pointer Type's

PointerType's  

lostmouse
160 1-16

In the forth paragraph of 7.3, the text explains about operator-> mechanics, and says:
    "The compiler keeps doing this recursively until it reaches a pointer to a built-in type [...]"
This is inaccurate. As the third section in page 185 indicates, the compiler is looking for a native pointer, not a pointer to a built-in type. I.e., pointer to a user class also stops the chain.
Actually, built-in types never stop the chain of operator->, as built-in types don't have members, hence, the member access operator (operator->) cannot be used with them.

"The compiler keeps doing this recursively until it reaches a native pointer [...]" 

Shmulik Flint
161 1-16

Near the bottom of the page:
"The reason is that the interaction between member function calls for the smart pointer for the pointed-to object can be extremely confusing."
This sentence doesn't make sense.

Something like:
"The reason is that the interaction between member function calls for the smart pointer and for the pointed-to object can be extremely confusing." 

Darren Ranalli
163 1-16


As discussed in Section 7.3, the Storage policy defines the ***pointer type.***
[according to definition on page 161 type of pointee_ is called "storage type", while type returned by operator->() is called "pointer type"]

As discussed in Section 7.3, the Storage policy defines the ***storage type.*** 

Grzegorz Jakacki
164 1-16

In source snip, Base is undefined.
virtual Base* Clone() = 0;

Should read:
virtual AbstractBase* Clone() = 0;
Likewise in the Concrete class:
virtual AbstractBase* Clone() 

Hal Jalikakik
167 1-16

'reference linking' is referred to as 'reference tracking'. Last paragraph, first sentence:
"The doubly linked list structure fits reference tracking like a glove."

change to:
"The doubly linked list structure fits reference linking like a glove." 

Darren Ranalli
169 1-16

Because they do not support value semantics, smart pointers with destructive copy cannot be stored in ***containers.***

Because they do not support value semantics, smart pointers with destructive copy cannot be stored in ***standard containers.***

Grzegorz Jakacki
171 1-16

Fun(&spWidget);
// okay, invokes operator* and obtains a
// pointer to Widget

Fun(&spWidget);
// okay, invokes operator& and obtains a
// pointer to Widget

 

Rodrigo Philander
171 1-16

"One reason is that exposing the address of the pointed-to object implies giving up any automatic ownership management."

However, operator& directly exposes the address of the pointer to the object, not the address of the pointed-to object. It indirectly exposes the address of the pointed-to object. But operator-> also exposes the address of the pointed object.  Hence, if this is a strong enough reason not to provide operator&, it should also be a strong enough reason not to provide operator->, which is absurd.

See erratum.
[Author's note: The idea is, if you can't totally achieve a purpose, it doesn't mean you shouldn't take reasonable action towards achieving it. You don't leave your house unlocked just because burglars can break in anyway.
In this particular case, more people are likely to write &obj than obj.operator->().] 

Manuel Menezes de Sequeira
174 1-16

With one user-defined conversion to the ***pointee type,*** most of the test expressions (except test 4) compile successfully and run as expected.
[here "pointee type" is T]

With one user-defined conversion to the ***raw pointer type,*** most of the test expressions (except test 4) compile successfully and run as expected.

Grzegorz Jakacki
176 1-16

They don't match because ***zero*** is not a pointer type.

They don't match because ***the type of literal zero*** is not a pointer type.

Grzegorz Jakacki
178 1-16

that returns a null pointer if and only if ***the pointee object*** is null

that returns a null pointer if and only if ***pointee_*** is null

 

Grzegorz Jakacki
181 1-16


SmartPtr(T* p)

explicit SmartPtr(T* p) 

Fraser Ross
182 1-16

Can initialization checking and checking before dereference be conceptually separated? No, because there are links between them. If you enforce strict checking upon initialization, then checking before dereference becomes redundant because the pointer is always valid.

[As GetImplRef(p) returns non-const reference to wrapped pointer it creates an encapsulation hole, which can be exploited to invalidate wrapped pointer even when the checking policy is strict.]

 

Grzegorz Jakacki
185 1-16

in the last paragraph, 'reference-linked' smart pointers are called 'reference-tracked' smart pointers:
"Reference-tracked smart pointers (Section 7.5.4)..."
and
"Therefore, every time you copy, assign, and destroy a reference-tracked smart pointer, ..."

change to:

"Reference-linked smart pointers (Section 7.5.4)..."

and

"Therefore, every time you copy, assign, or destroy a reference-linked smart pointer, ..." 

Darren Ranalli
186 1-16

Source code and first paragraph of page 187:
if (prev_ == next_)
This would delete the pointee_ if there are only two nodes in the list.  In fact, prev_ == next_ occurs in two cases: a single node in the circular list, or two nodes in the circular list.

if (prev_ == this)
(The text in page 187 should be corrected.) 

Manuel Menezes de Sequeira
189 1-16

near the bottom of the page:
ArrayStorage, which uses operator delete[] inside Release

ArrayStorage, which uses operator delete[] inside Destroy 

Darren Ranalli
189 1-16

First bullet, at bottom of page incorrectly refers to Release.

Replace Release with Destroy

Rob Stewart
189 1-16

At the ned of the page it is said that 3 other Storage policies are defined in Loki (ArrayStorage, LockedStorage, HeapStorage) but in fact there isn't any.

Remove "In adition to DefaultSPStorage, Loki also defines the following:" and replace it with "In adition to DefaultSPStorage, Loki could/will also define the following:" 

Enrico Spinielli
191 1-16

OwnershipImplImpl

OwnershipImpl 

Jacques Bouchard
191 1-16

Table 7.2: Missing dot between object name and method name: ownershipImpl Release(val);

ownershipImpl.Release(val); 

Pavel Zeldin
191 1-16

bottom of this page:
{;

}; 

lostmouse
191 1-16

wrong font in bool unique (8th line)

 

Waldemar Rosenbach
192 1-16

The underlying pointer type of SmartPtr is dictated by its Storage policy and is ***StorageImpl::PointerType.***

The underlying pointer type of SmartPtr is dictated by its Storage policy and is ***StorageImpl::StorageType.***

Grzegorz Jakacki
192 1-16


public:

protected: 

Fraser Ross
199 1-16

The CreateDocument member of DocumentManager is private when it should be public.

DocumentManager should be as follows:


class DocumentManager
{
    ...
public:
    Document* NewDocument();
    virtual Document* CreateDocument() = 0;
private:
    std::list listOfDocs_;
};

 

Trebor Rude
199 1-16

The correction to the scope of the pure virtual function is not necessary.

 

Fraser Ross
202 1-16

In the middle of the page:

namespace DrawingType
{
    ...
};

The semicolon is superfluous.

namespace DrawingType
{
    ...
}

 

Boris Pulatov
203 1-16

[...] the switch statement in Drawing::Save. [...]

[...] the switch statement in Drawing::Load. [...] 

Laurent Richard
203 1-16

in the second bullet-point:
"For one thing, the implementation file of Drawing::Save must include[...]"

should be:
"For one thing, the implementation file of Drawing::Load must include[...]" 

Darren Ranalli
204 1-16

Minor anality: in the ShapeFactory class declaration in the middle of the page, the method argument names are capitalized, breaking the formatting convention used throughout the book.

Change ShapeId and CreateFn to shapeId and createFn.
[Author's note: No anality at all! Consistency is important. Thanks for the input!] 

Darren Ranalli
205 1-16

The insert member function we called returns another pair, this time containing an iterator (which refers to the element just inserted) and a bool that is true if ***the value didn't exist before.***

The insert member function we called returns another pair, this time containing an iterator (which refers to the element just inserted) and a bool that is true if ***map didn't contain a pair having an equivalent key.***

Grzegorz Jakacki
208 1-16

typedef std::map<
        IdentifierType, AbstractProduct>
    AssocMap;

typedef std::map AssocMap;

 

chocolateboy
209 1-16

In the middle of the page:

: public FactoryErrorPolicy<...>

This line should be in bold as other additions and changes to this code fragment. 

Boris Pulatov
210 1-16

StaticProductType*  OnUnknownType(
    const IdentifierType& id)

static ProductType* OnUnknownType(const IdentifierType& id)


Note: Loki library reads: static AbstractProduct* OnUnknownType(IdentifierType) 

Milivoj Davidov
210 1-16

Inside the definition of class Exception:

const IdentifierType GetId()
{
    return unknownId_;
};

This are not errors per se, but:
1. There doesn't seem to be a good reason to return a const object. Perhaps the author meant to return a const reference.
2. The semicolon after the closing bracket is superfluous. 

Boris Pulatov
212 1-16

First text paragraph:
you must implement a similar Clone function for each class you add to the hierarchy.

you must implement a similar Clone function for each concrete class you add to the hierarchy. 

Manuel Menezes de Sequeira
213 1-16

The DoClone member of Shape is private when it should be protected.

Change "private" to "protected" in the first line. Change private to protected in the declaration of Shape. Change the comment to match (or delete it, it doesn't add any more information than the keyword). Change "private" to "protected" two lines below the Shape declaration. 

Trebor Rude
213 1-16

The correction to the scope of the pure virtual function is not necessary.

 

Fraser Ross
215 1-16

typedef SingletonHolder
<
    Factory
    <
        Shape, std::string, Functor
    >
>
ShapeFactory

typedef SingletonHolder
<
    Factory
    <
        Shape, std::string, Functor
    >
>
ShapeFactory


but I could not compile this on Metrowerks 7.0. I think that class Functor needs some fine tuning to work with std::map 

Florin Chertes
221 1-16

Finally, you initialize a pointer to AbstractEnemyFactory with ***the appropriate concrete class:***

Finally, you initialize a pointer to AbstractEnemyFactory with ***a pointer to an object of appropriate concrete class:***

 

Grzegorz Jakacki
224 1-16

AbstractFactory<...>

AFUnit<...>
[Author's note: Also thanks to Jacques Bouchard.] 

Pavel Zeldin
224 1-16

Second text paragraph:
Each defines one pure virtual member function Create, so AbstractEnemyFactory has three Create overloads.

Each defines one pure virtual member function DoCreate, so AbstractEnemyFactory has three DoCreate overloads.
[Author's note: Also thanks to Eelis van der Weegen. 

Manuel Menezes de Sequeira
228 1-16

Regarding the ConcreteFactory definition near the top of the page:
There is no reason at this point in the chapter for the TList template argument to default to AbstractFact::ProductList, and it's confusing for the reader, who has not yet read about prototype-based abstract factories.

Change the last template argument from:

    class TList = typename AbstractFact::ProductList

to:

    class TList

 

Darren Ranalli
228 1-16

in the penultimate complete paragraph on the page: "Creation from scratch needs knowledge..."

grammatically better: "Creation from scratch requires knowledge..." 

Darren Ranalli
228 1-16

Two unrelated errors on the fourth line of the code:

template <class, class> class Creator = OPNewFactoryUnit

Should be:

template <class, class> class Creator = OpNewFactoryUnit,

 

Boris Pulatov
229 1-16

OpNewCreator appears in two places in Figure 9.3, without having been defined in the text.

OpNewCreator should be OpNewFactoryUnit

Kenny Knecht
230 1-16

in Soldier* MakeSoldier()
pProtoSoldier_->Clone();

protoSoldier_->Clone(); 

Andrea Bugin
231 1-16

template <class ConcreteProduct, class Base>
...
protected;
    ...
public;
    ...

template <class ConcreteProduct, class Base>
...
protected:
    ...
public:
    ...

 

Giovanni Costagliola
231 1-16

In parenthetical reference to Section 9.3, there's an incorrect reference to AbstractFact.

Change all AbstractFacts" to AbstractFactorys. 

Rob Stewart
231 1-16

In PrototypeFactoryUnit's definition, the typedef for ProductList is ill-formed.

Change the line to:
typedef typename Base::ProductList::Tail ProductList; 

Rob Stewart
231 1-16

Immediately after the first code block:
"(Recall from AbstractFact's definition in Section 9.3..."
this is the wrong section number

change "Section 9.3" to "Section 9.2"
(Note that AbstractFact should also be changed to AbstractFactory, as per another erratum.) 

Darren Ranalli
231 1-16

In the PrototypeFactoryUnit template declaration near the middle of the page:

template <class ConcreteProduct, class Base>

The first template argument is not a concrete product type; rather, it is the abstract product type, the same type that is deduced and typedef'd as AbstractProduct in the public section of the class. Calling the template argument ConcreteProduct is incorrect.

Change the template argument list to:

template <class AbstractProduct, class Base>



 

Darren Ranalli
231 1-16

At Abstract Factory, section 9.4, the constructor for PrototypeFactoryUnit is something like:

PrototypeFactoryUnit( AbstractProduct * p = 0)...

But let's say we have a factory for Soldier, Monster and SuperMonster.
The generated code would contain three constructors:

PrototypeFactoryUnit< Soldier,...>(
    Soldier * = 0);
PrototypeFactoryUnit< Monster,...>(
    Monster * = 0);
PrototypeFactoryUnit< SuperMonster,...>(
    SuperMonster * = 0);

Having an instance of PrototypeFactoryUnit for Soldier, Monster and SuperMonster it's impossible to pass a pointer to initialize PrototypeFactoryUnit for these three types.

The constuctor for PrototypeFactoryUnit should be default: PrototypeFactoryUnit() ...

John Torjo
231 1-16

The GetPrototype method should use the same mechanism as DoCreate to disambiguate method calls.

AbstractProduct* GetPrototype(Type2Type) const

 

Ernesto García García
231 1-16

template <class /*AbstractProduct/*>

template <class /*AbstractProduct*/> 

Thomas Schell
231 1-16

template <class U>
void GetPrototype (AbstractProduct*& p)

template <class U>
void GetPrototype (U*& p) 

Thomas Schell
232 1-16

Pages 232 and 233: AFUnit

AbstractFactoryUnit 

Manuel Menezes de Sequeira
232 1-16

at the bottom of the page:
"(pointers or references to AFUnit"
AFUnit should be AbstractFactoryUnit

change AFUnit to AbstractFactoryUnit
(there are two more instances of AFUnit in the middle of the following page, p.233; change those too) 

Darren Ranalli
232 1-16

just before the last code block on the page:
"To define a concrete factory, all you have to write..."
This sentence is a bit too general; we're not defining just any concrete factory, we're defining a concrete prototype-based factory.

something like:
"To define a concrete prototype-based factory, all you have to write..." 

Darren Ranalli
233 1-16

Last source code: SuperMonster>

SuperMonster)> 

Manuel Menezes de Sequeira
234 1-16

In the last code segment:

PrototypeFactoryUnit,

 

Remove the comma:

PrototypeFactoryUnit

 

Boris Pulatov
235 1-16

Adding new classes is easy. You derive from a ***leaf*** class and implement the needed virtual functions.

Adding new classes is easy. You derive from a  class and implement the needed virtual functions.
(remove "leaf")

 

Grzegorz Jakacki
238 1-16

Line after source code:
because of to a

because of a 

Manuel Menezes de Sequeira
240 1-16

Middle of the page: DocStatsis

DocStats is 

Manuel Menezes de Sequeira
243 1-16

At the bottom of the page:

class DocElementVisitor
{
    virtual void VisitParagraph(Paragraph&) = 0;
    ...
};

class DocElementVisitor
{
public:
    virtual void VisitParagraph(Paragraph&) = 0;
    ...
};

 

Boris Pulatov
244 1-16

in the third bullet-point:
"...as opposed to a pure, function, ..."

"...as opposed to a pure virtual function, ..." 

Darren Ranalli
245 1-16

Visitor& v

DocElementVisitor& v 

Jacques Bouchard
245 1-16

virtual void ~DocElementVisitor() {}

virtual ~DocElementVisitor() {} 

Milivoj Davidov
245 1-16

requirementcould

requirement could 

Manuel Menezes de Sequeira
248 1-16

Ralph Gamma

Erich Gamma 

Bob Soper
250 1-16

saddition (very first word on this page)

addition 

Roland Weiss
250 1-16

Middle page:
you first derive your ConcreteVisitor

you first derive your SomeVisitor 

Manuel Menezes de Sequeira
251 1-16

boot (seventh word on this page)

root
[Author's note: Actually the intent was boot in the sense of bootstrap.] 

Roland Weiss
251 1-16

In the first bullet point:
"Declare a virtual pure Accept function that takes a reference to a Visitor..."
the words 'pure' and 'virtual' are transposed, and Accept takes a reference to BaseVisitor, not Visitor

"Declare a pure virtual Accept function that takes a reference to a BaseVisitor..." 

Darren Ranalli
251 1-16

in the paragraph after the code block:
"...T::Accept's implementation applies dynamic_cast*>..."
Visitor is misspelled.

"...T::Accept's implementation applies dynamic_cast*>..." 

Darren Ranalli
251 1-16

in the paragraph after the code block:
"...T::Accept bounces back to the Visitor::Visit."
This is grammatically incorrect.

"...T::Accept bounces back to Visitor::Visit." 

Darren Ranalli
251 1-16

in the paragraph after the code block:
"...simply defining Accept in the Base Visitable class..."
there's a space in the middle of the BaseVisitable class name

"...simply defining Accept in the BaseVisitable class..." 

Darren Ranalli
252 1-16

First full paragraph, second to last sentence:
"...base of the hierarchy, in BaseVisitor."

Change BaseVisitor to BaseVisitable

Rob Stewart
253 1-16

The AcceptImpl code is "calling" the Visitor template with only one parameter.

if (Visitor* p = dynamic_castT>*>(&guest))

That causes an error if we want to use a return type other than void.

Add the second parameter:

if (Visitor* p = dynamic_cast*>(&guest))

See SourceForge.net->Loki Bug->Request ID 588033 for an example.
[Author's note: This bug has been fixed in Loki. Thank you for your bug report.] 

Solvi de Yarza
254 1-16

virtual ReturnType Accept Visitor& v)
{
...
-> missing return
}

 

Thomas Schell
256 1-16

Middle of the page:
CyclicVisitor depends ...

MyVisitor depends ... 

Manuel Menezes de Sequeira
256 1-16

Private::VisitorBinder::Result
-> is not in Visitor.h even though there is a reference in the book

 

Thomas Schell
256 1-16

Members of class CyclicVisitor should be declared publically, as in Loki's Visitor.h.

 

Ryan Leslie
257 1-16

virtual void Visit(MyVisitor&) = 0;

virtual void Accept(MyVisitor&) = 0;

 

Jacques Bouchard
257 1-16

Define a virtual pure function Visit

Define a virtual pure function Accept 

Jacques Bouchard
257 1-16

In the first paragraph, there is a reference to a Define a virtual pure function DEFINE_CYCLIC_VISITABLE macro. This macro is never defined or explained in the text (although it's easy enough to find in the Loki source)

add explanation of DEFINE_CYCLIC_VISITABLE 

Darren Ranalli
257 1-16

Darren Ranalli (printings 1-8):
DEFINE_CYCLIC_VISITABLE (...) appears out of nowhere (you can easily find it in the loki source-code).  

 

Thomas Schell
261 1-16

in the first sentence of the second bullet point:
"The first template parameter of Visitor and BaseVisitable is the return type..."
the return type is not the first template parameter of Visitor.

"The second template parameter of Visitor and the first template parameter of BaseVisitable are the return type..." 

Darren Ranalli
262 1-16

in the first sentence:
"...derive your visitable hierarchy from BaseVisitorImpl."
It's the visitor that should derive from BaseVisitorImpl, not the visitable hierarchy.

"...derive your visitor from BaseVisitorImpl." 

Darren Ranalli
266 1-16

In the code:

else if (Poly* p1 = dynamic_cast(&lhs))
{
    if (Rectangle* p2 = dynamic_cast(&rhs))
        DoHatchArea2(*p2, *p1);

 

Should be DoHatchArea3 here (not 2):

else if (Poly* p1 = dynamic_cast(&lhs))
{
    if (Rectangle* p2 = dynamic_cast(&rhs))
        DoHatchArea3(*p2, *p1);

 

Boris Pulatov
266 1-16


if (Rectangle* p1 = dynamic_cast(&rhs))
{
  if (Rectangle* p2 = dynamic_cast(&rhs))
  DoHatchArea1(*p1, *p2);
  else if (Ellipse p2 = dynamic_cast(&rhs))
  DoHatchArea2(*p1, *p2);
  else if (Poly p2 = dynamic_cast(&rhs))
  DoHatchArea3(*p1, *p2);



if (Rectangle* p1 = dynamic_cast(&rhs))
{
  if (Rectangle* p2 = dynamic_cast(&rhs))
  DoHatchArea1(*p1, *p2);
  else if (Ellipse* p2 = dynamic_cast(&rhs))
  DoHatchArea2(*p1, *p2);
  else if (Poly* p2 = dynamic_cast(&rhs))
  DoHatchArea3(*p1, *p2); 

Chandra Shekhar Kumar
267 1-16

The size grows exponentially as you add more classes.

The size grows quadratically as you add more classes. 

Grzegorz Jakacki
268 1-16

StaticDispatcher::Go needs to pass the ResultType template parameter to StaticDispatcher in the call to DispatchRhs and in the recursive call to itself.


return StaticDispatcher     NullType, BaseRhs, TypesRhs>::DispatchRhs(
        *p1, rhs, exec);
...
return StaticDispatcher     Tail, BaseRhs, TypesRhs>::Go(
        lhs, rhs, exec);


return StaticDispatcher     BaseRhs, TypesRhs, ResultType>::DispatchRhs(
        *p1, rhs, exec);
...
return StaticDispatcher     BaseRhs, TypesRhs, ResultType>::Go(
        lhs, rhs, exec);

 

Milivoj Davidov
268 1-16

In the list of StaticDispatcher template arguments:

  class TypesRhs = TypesLhs


There is a missing comma.

  class TypesRhs = TypesLhs,

 

Darren Ranalli
268 1-16

The NullType as Parameters for the Template would call the Error-Handling-Specialization.

(The same applies to Page 269)

Use TypesLhs instead of NullType.

In general I think the fact that the Parameter is of no use points out that there should be a Helper-Template-Class:


template<
  class Executor,
  class BaseLhs,
  class TypesLhs,
  class BaseRhs = BaseLhs,
  class TypesRhs = TypesLhs,
  typename ResultType = void
>
class StaticDispatcher
{
  typedef typename TypesLhs::Head Head;
  typedef typename TypesLhs::Tail Tail;
public:
  static ResultType Go(BaseLhs& lhs, BaseRhs& rhs, Executor exec)
  {
    if (Head* p1 = dynamic_cast(&lhs))
    {
      return StaticDispatcherHelper TypesRhs, ResultType>::DispatchRhs(*p1, rhs, exec);
    }
    else
    {
      return StaticDispatcher BaseRhs, TypesRhs, ResultType>::Go(lhs, rhs, exec);
    }
  }
};

template<
  class Executor,
  class BaseRhs = BaseLhs,
  class TypesRhs = TypesLhs,
  typename ResultType = void
>
class StaticDispatcherHelper
{
public:
  template <class SomeLhs>
  static ResultType DispatchRhs(SomeLhs& lhs, BaseRhs& rhs,
Executor exec)
  {
    typedef typename TypesRhs::Head Head;
    typedef typename TypesRhs::Tail Tail;

    if (Head* p2 = dynamic_cast(&rhs))
    {
      return exec.Fire(lhs, *p2);
    }
    else
    {
      return StaticDispatcherHelper Tail, ResultType>::DispatchRhs(lhs, rhs, exec);
    }
  }
};

 

Christoph Krc
268 1-16

if (Head* p1 = ...
return StaticDispatcher(...

if (Head* p1 = ...
return StaticDispatcher<... 

Thomas Schell
269 1-16

StaticDispatcher::DispatchRhs - same as Sta­ticDispatcher::Go on page 268.

return StaticDispatcher     NullType, BaseRhs, Tail>::DispatchRhs(
        lhs, rhs, exec);

return StaticDispatcher     BaseRhs, Tail, ResultType>::DispatchRhs(
        lhs, rhs, exec);

 

Milivoj Davidov
270 1-16

First paragraph:
"[...] manages to generate an exponential amount of code [...]"
The amount of code does not grow exponentially, but polynomially (n^2).

See erratum. 

Manuel Menezes de Sequeira
270 1-16

In the code block at the bottom of the page, TypesRhs is an unused template parameter.
The precedent set by the preceding code block (on the same page) is to omit unused template parameters (its template argument list does not include TypesLhs).

remove the following line:

  class TypesRhs,

 

Darren Ranalli
270 1-16


Go must return ResultType.
Go must be in public:.

StaticDispatcher has a hyphen missing at the line break.

The TypesLhs parameter is always NullType with DispatchRhs.

public:
static ResultType Go(BaseLhs& lhs, BaseRhs& rhs, Executor exec)
{
  return exec.OnError(lhs, rhs);
}


template
<
  class Executor,
  class BaseLhs,
  class BaseRhs,
  typename ResultType
>
class StaticDispatcher
{
public:

Fraser Ross
271 1-16


DispatchRhs must return ResultType.
Executor function parameter is usually not a reference parameter.

static ResultType DispatchRhs(BaseLhs& lhs, BaseRhs& rhs,
  Executor exec)
{
  return exec.OnError(lhs, rhs);

Fraser Ross
272 1-16

The sorting of the Typelist is wrong:

typedef typename DerivedToFront<
        typename TypesLhs::Head>::Result
    Head;
typedef typename DerivedToFront<
        typename TypesLhs::Tail>::Result
    Tail;

This code shouldn't even compile since TypesLhs::Head is not a typelist.


typedef typename DerivedToFront<
    typename TypesLhs>::Result::Head Head;
typedef typename DerivedToFront<
    typename TypesLhs>::Result::Tail Head;

Or even better

typedef typename DerivedToFront<
        typename TypesLhs>::Result
    SortedTypesLhs;
typedef typename SortedTypesLhs::Head
    Head;
typedef typename SortedTypesLhs::Tail
    Tail;

 

Christoph Krc
272 1-16

The code-snippet sorts only the Typelist for the first Argument.

Implement the same kind of Typelist-Sorting in  "DispatchRhs". 

Christoph Krc
274 1-16

Macro name typo.

TYPELIST_2(Rectangle, Ellipse, Poly), // TypesLhs
TYPELIST_2(Rectangle, Ellipse, Poly), // TypesRhs

TYPELIST_3(Rectangle, Ellipse, Poly), // TypesLhs
TYPELIST_3(Rectangle, Ellipse, Poly), // TypesRhs

 

Milivoj Davidov
275 1-16

Source code excerpt on pages 275 and 276: ResultType template parameter is missing in the declaration & implementation of InvocationTraits template class and StaticDispatcher::DispatchRhs member function.

1. DoDispatch's return type should be ResultType, and its implementation needs to be changed to return whatever exec.Fire() returns.

2. CallTraits type definition (inside DispatchRhs) and recursive call to DispatchRhs need to have ResultType template parameter added.

1. Typo: True should be replaced with true

Milivoj Davidov
275 1-16

What's the Boolean condition that determines whether or not argument swapping is needed? The algorithm selects the types in ***TL2*** only at indices greater than or equal to the index of the type in ***TL1.***

What's the Boolean condition that determines whether or not argument swapping is needed? The algorithm selects the types in ***TypesRhs*** only at indices greater than or equal to the index of the type in ***TypesLhs.***

 

Grzegorz Jakacki
275 1-16

The implementation of the symmetric StaticDispatcher given in the book on pages 275-276 doesn't work (even after other errata are applied), because the way it recurses leaves the two lists TypesLhs and TypesRhs with SomeLhs/SomeRhs on their respective Heads. IndexOf<> therefore always returns zero for both.

Use StaticDispatcher from MultiMethods.h in Loki 0.1.4 (or later), which has been corrected to retain the original type lists while two template member functions DispatchLhs and DispatchRhs iterate through the list.

class StaticDispatcher
{
    //... see MultiMethods.h for complete class
    template <class Head, class Tail, class SomeLhs>
    static ResultType DispatchRhs(SomeLhs& lhs, BaseRhs& rhs,
        Executor exec, Typelist)
    {            
        if (Head* p2 = dynamic_cast(&rhs))
        {
            Int2Type<(symmetric &&
              int(TL::IndexOf::value) <
              int(TL::IndexOf::value))> i2t;

            typedef Private::InvocationTraits<
                SomeLhs, Head, Executor, ResultType> CallTraits;
                    
            return CallTraits::DoDispatch(lhs, *p2, exec, i2t);
        }
        return DispatchRhs(lhs, rhs, exec, Tail());
    }
    template <class Head, class Tail>
    static ResultType DispatchLhs(BaseLhs& lhs, BaseRhs& rhs,
        Executor exec, Typelist)
    {            
        if (Head* p1 = dynamic_cast(&lhs))
        {
            return DispatchRhs(*p1, rhs, exec, TypesRhs());
        }
        return DispatchLhs(lhs, rhs, exec, Tail());
    }
public:
    static ResultType Go(BaseLhs& lhs, BaseRhs& rhs,
        Executor exec)
    { return DispatchLhs(lhs, rhs, exec, TypesLhs()); }
};

 

Tim Mensch
276 1-16

Pages 276 and 277: OrderedTypeInfo

TypeInfo 

Manuel Menezes de Sequeira
276 1-16

In the code block at the top of the page, the definition of StaticDispatcher::DispatchRhs is missing its SomeLhs template parameter.

Prefix the DispatchRhs function definition with:

template <class SomeLhs>

and replace BaseLhs with SomeLhs in the function argument list, the enum, and the typedef

Darren Ranalli
277 1-16

OrderedTypeInfo

Change all references to OrderedTypeInfo to TypeInfo, the class defined in Chapter 2. 

Rob Stewart
278 1-16

The 2nd source code on page 278 reads:

template <class SomeLhs, SomeRhs>

template <class SomeLhs, class SomeRhs>

 

reported by Tatsuya Watanabe (submitted by M.Murakami)
280 1-16

In the fourth full paragraph:
"You can easily transform static functions in functions with external linkage..."
'in' should be 'into'.

"You can easily transform static functions into functions with external linkage..." 

Darren Ranalli
280 1-16

line 3: FnDoubleDispatcher::Add
FnDoubleDispatcher has not been introduced yet

BasicDispatcher::Add

 

Andrea Bugin
281 1-16

source code on page 281 reads:

ResultType = void>

should be:

typename ResultType = void>

 

reported by Hiroaki Itoh (submitted by M.Murakami)
281 1-16

BaseDispatcher backEnd_;

BasicDispatcher backEnd_;

 

Milivoj Davidov
281 1-16

disp.Add();

disp.Add(); 

Milivoj Davidov
281 1-16

BaseDispatcher in FnDispatcher's definition and the paragraph following it.

Change BaseDispatcher to BasicDispatcher

Rob Stewart
281 1-16

at the end of the page

void HatchRectangle(Rectangle& lhs, Poly& rhs)
{
    ...
}
Dispatcher disp;
disp.Add();

void Hatch(Rectangle& lhs, Poly& rhs)
{
    ...
}
Dispatcher disp;
disp.Add();



or

void HatchRectangle(Rectangle& lhs, Poly& rhs)
{
    ...
}

Dispatcher disp;
disp.Add();

 

Andrea Bugin
281 1-16


return backEnd_ ...
No need for return keyword.

backEnd_ ... 

Fraser Ross
282 1-16

In the middle of the page:

bool Add()
{

Should be:

void Add()
{

 

Boris Pulatov
282 1-16

In the code segment:

... Trampoline as before ...
static void TrampolineR(BaseRhs& rhs, BaseLhs& lhs)
{

TrampolineR should return ReturnType:

... Trampoline as before ...
static ResultType TrampolineR(BaseRhs& rhs, BaseLhs& lhs)

Boris Pulatov
282 1-16


backEnd_. missing before Add twice.

backEnd_.Add... 

Fraser Ross
283 1-16

That is, make the dispatcher a policy for the ***classes*** FnDispatcher and FunctorDispatcher, much as we did with the casting strategy.

That is, make the dispatcher a policy for the ***class templates*** FnDispatcher and FunctorDispatcher, much as we did with the casting strategy.

Grzegorz Jakacki
284 1-16

Near the end of the code block in the middle of the page:

    virtual FunctorImplType* Clone()const

There is no space between Clone() and const. Even though it compiles, it seems like bad form.

virtual FunctorImplType* Clone() const

 

Darren Ranalli
284 1-16


Missing keyword typename before ResultType template parameter.

"member function defines"

typename ResultType = void>

"member function template defines" 

Fraser Ross
287 1-16

The paragraph below the code:

...If you try to register... converting a Shape & to a RoundedRectangle & should read

converting RoundedRectangle & to Shape &.

 

Steven Feng
288 1-16

Second code fragment:

template
<
    ...
    ResultType = void,
    ...
>

Add typename:

template
<
    ...
    typename ResultType = void,
    ...
>

 

Boris Pulatov
288 1-16


Various typos in non-bold parts of FunctorDispatcher.

See P284. 

Fraser Ross
289 1-16

Last paragraph:
Text says ShapeCast, but the code uses ShapeCaster.

Use ShapeCaster throughout. 

Boris Pulatov
290 1-16

Missing back-slash:

#define IMPLEMENT_INDEXABLE_CLASS(SomeClass)

#define IMPLEMENT_INDEXABLE_CLASS(SomeClass) \

 

Milivoj Davidov
292 1-16

line 4

template<class SomeLhs, SomeRhs>

template<class SomeLhs, class SomeRhs>

 

Andrea Bugin
292 1-16

BasicFastDispatcher can incorrectly assign the same ID to different classes, because it keeps track of the next ID in two different ways: columns_ and the size of callbacks_.

Replace columns_ with nextIndex_ and replace

callbacks_.push_back(Row());

with

callbacks_.resize(++nextIndex_);

 

Kim Wallmark
292 1-16


Kim Wallmark's comment is wrong.

Two improvements can be made:
idxRhs = thisRow.size() - 1; can be idxRhs = columns_ - 1;
thisRow.resize(idxRhs + 1);
can be thisRow.resize(columns_);

 

Fraser Ross
292 1-16


thisRow.size() <= idxRhs can be thisRow.size() < columns_

 

Fraser Ross
293 1-16

First code segment, third line from the end:

return callbacks_[idxLhs][idxRhs].callback_(lhs, rhs);

Should be:

return callbacks_[idxLhs][idxRhs](lhs, rhs);

 

Boris Pulatov
293 1-16


Last sentence of first paragraph add

and to the left hand and right hand base class types. 

Fraser Ross
295 1-16

Footnote 7.

Change  OrderedTypeInfo to TypeInfo, the class defined in Chapter 2. 

Rob Stewart
295 1-16

You can generalize the map-based dispatcher to one that is keyed by a vector of ***std:: type_info*** objects (as opposed to a std::pair).

You can generalize the map-based dispatcher to one that is keyed by a vector of ***TypeInfo*** objects (as opposed to a std::pair).

Grzegorz Jakacki
297 1-16

There is no BasicFastDispatcher in Loki

Jacques Bouchard
297 1-16

Missing template parameter bool symmetric in class StaticDispatcher

Insert a new bool symmetric template parameter for StaticDispatcher between Executor and BaseLhs.
[Author's note: Also thanks to Jacques Bouchard.] 

Rob Stewart
297 1-16

Names of dispatchers (brute-force, map-based) do not match names in the table (static, logarithmic).

 

Grzegorz Jakacki
298 1-16

Missing parameter false after:
TYPELIST_2(Rectangle, Ellipse)

Add false 

Jacques Bouchard
298 1-16

bool result = disp.Go(*pSh, *pDev)

bool result = disp.Go(*pSh, *pDev, Painter())

 

Jacques Bouchard
298 1-16

In the second TYPELIST_2 near the center of the page, there is an extraneous & after the word Printer.

Remove the &, so that the line reads:

  TYPELIST_2(Printer, Screen),

 

Darren Ranalli
298 1-16

BasicDispatcher and BasicFastDispatcher implement dynamic dispatchers that allow users to add ***handler functions*** at runtime. [handlers can be functors, not necessarily functions]

BasicDispatcher and BasicFastDispatcher implement dynamic dispatchers that allow users to add ***handlers*** at runtime.

Grzegorz Jakacki
299 1-16

In the first sentence of the penultimate bullet-point:
"Both ... provide an Add member function or their primitive handler type."
'or' should be 'for'.

Change to:
"Both...provide an Add member function for their primitive handler type." 

Darren Ranalli
305 1-16

Edgar Dijkstra

Edsger W. Dijkstra 

Diethard Michaelis
305 1-16

"Mutual Exclusive," in the third paragraph of A.4, is incorrect and poor grammar.

Change "Exclusive" to "Exclusion." 

Rob Stewart
309 1-16

Last paragraph:
"All implementations of ThreadingModel support a unique sintactic interface."
Strictly, this is not true, since ClassLevelLockable::Lock has a default constructor, which is missing in ObjectLevelLockable::Lock.

See erratum. 

Manuel Menezes de Sequeira