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 specialization (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(CompileTimeChecker<(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 SupportsBitwiseCopy 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 Functor s"): 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 AbstractFact s" to AbstractFactory s.
|
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 StaticDispatcher::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 |