diff --git a/src/common/typelist.hpp b/src/common/typelist.hpp index b7c28995f..11bfd355c 100644 --- a/src/common/typelist.hpp +++ b/src/common/typelist.hpp @@ -20,7 +20,7 @@ ==================================================================== This code is heavily inspired by - The Loki Library (loki-lib/trunk/include/loki/Singleton.h) + The Loki Library (loki-lib/trunk/include/loki/Sequence.h) Copyright (c) 2001 by Andrei Alexandrescu Copyright (c) 2005 by Peter Kümmel This Loki code accompanies the book: diff --git a/src/common/visitor.hpp b/src/common/visitor.hpp index 20dfabaeb..ed37c1963 100644 --- a/src/common/visitor.hpp +++ b/src/common/visitor.hpp @@ -29,8 +29,7 @@ This code is heavily inspired by Credits for many further implementation ideas go to Cooperative Visitor: A Template Technique for Visitor Creation - by Anand Shankar Krishnamoorthi - July 11, 2007 + by Anand Shankar Krishnamoorthi (July 2007) http://www.artima.com/cppsource/cooperative_visitor.html */ @@ -52,10 +51,16 @@ Credits for many further implementation ideas go to **
The ''Visitor Pattern'' is a special form of //double dispatch// — selecting the function actually to be executed at runtime based both on the concrete type of some tool object //and // the target this tool is applied to. The rationale is to separate some specific implementation details from the basic infrastructure and the global interfaces, which can be limited to describe the fundamental properties and operations, while all details relevant only for some specific sub-problem can be kept together encapsulated in a tool implementation class. Typically, there is some iteration mechanism, allowing to apply these tools to all objects in a given container, a collection or object graph, without knowing the exact type of the target and tool objects. See the [[Visitor Pattern design discussion|VisitorUse]]
!Problems with Visitor
@@ -3992,13 +3992,13 @@ A good starting point for understanding our library implementation of the visito
* the objects in the {{{Visitable}}} hierarchy implement an {{{apply(Tool&)}}}-function. This function needs to be implemented in a very specific manner, thus the {{{DEFINE_PROCESSABLE_BY}}} macro should be used when possible to insert the definition into a concrete {{{Visitable}}} class.
* similar to the acyclic visitor, the concrete visiting tool classes inherit from {{{Applicable<TARGET, ...>}}} marker base classes, where the template parameter {{{TARGET}}} is the concrete Visitable type this tool wants to treat, either directly by defining a {{{treat(ConcreteVisitable&)}}}, or by falling back to some more general {{{treat(...)}}} function.
* consequently our implementation is //rather not acyclic// — the concrete tool implementation depends on the full definition (header) of all concrete Visitables, but we avoid cyclic dependencies on the interface level. By using a typelist technique inspired by Loki, we can concentrate these dependencies in one single header file, which keeps things maintainable.
-* we use the {{{Applicable<TARGET,TOOLImpl>}}} marker base classes to drive the generation of Dispatcher classes, each of which holds a table of trampoline functions for carrying out the actual double dispatch at call time. Each concrete Visitable using the {{{DEFINE_PROCESSABLE_BY}}}-macro generates a separate Dispatcher table containing slots for each concrete tool implementation class. To store and access the index position for these "call slots", we use a tag associated with the concrete visiting tool class, which can be retrieved by going though the tool's vtable
+* we use the {{{Applicable<TARGET, ...>}}} marker base classes to drive the generation of Dispatcher classes, each of which holds a table of trampoline functions for carrying out the actual double dispatch at call time. Each concrete Visitable using the {{{DEFINE_PROCESSABLE_BY}}}-macro generates a separate Dispatcher table containing slots for each concrete tool implementation class. To store and access the index position for these "call slots", we use a tag associated with the concrete visiting tool class, which can be retrieved by going though the tool's vtable
* __runtime cost__: the concrete tool's ctor stores the trampoline pointers (this could be optimized to be a "once per class" initialisation). Then, for each call, we have 2 virtual function calls and a lookup and call of the trampoline function, typically resulting in another virtual function call for resolving the {{{treat(..)}}} function on the concrete tool class
* __extension possibilities__: while this system may seem complicated, you should note that it was designed with special focus on extension and implementing against interfaces:
** not every Visitable subclass needs a separate Dispatcher. As a rule of thumb, only when some type needs to be treated separately within some concrete visiting tool (i.e. when there is the need of a {{{treat(MySpecialVisitable&)}}}), then this class should use the {{{DEFINE_PROCESSABLE_BY}}}-macro and thus define it's own {{{apply()}}}-function and Dispatcher. In all other cases, it is sufficient just to extend some existing Visitable, which thus will act as an interface with regards to the visiting tools.
** because the possibility of utilizing virtual {{{treat(...)}}} functions, not every concrete visiting tool class needs to define a set of {{{Applicable<...>}}} base classes (and thus get a separate dispatcher slot). We need such only for each //unique set// of Applicables. All other concrete tools can extend existing tool implementations, sharing and partially extending the same set of virtual {{{treat()}}}-functions.
** when adding a new "first class" Visitable, i.e. a concrete target class that needs to be treated separately in some visiting tool, the user needs to include the {{{DEFINE_PROCESSABLE_BY}}} macro and needs to make sure that all existing "first class" tool implementation classes include the Applicable base class for this new type. In this respect, our implementation is clearly "cyclic". (Generally speaking, the visitor pattern should not be used when the hierarchy of target objects is frequently extended and remoulded). But, when using the typelist facillity to define the Applicable base classes, we'll have one header file defining these collection of Applicables and thus we just need to add our new concrete Visitable to this header and recompile all tool implementation classes.
-** when creating a new "~Visitable-and-Tool" hierarchy, the user should derive (or typedef) and parametrize the {{{Visitable}}}, {{{Tool}}} and {{{Applicable}}} templates, typically into a new namespace.
+** when creating a new "~Visitable-and-Tool" hierarchy, the user should derive (or typedef) and parametrize the {{{Visitable}}}, {{{Tool}}} and {{{Applicable}}} templates, typically into a new namespace. An example can be seen in {{{proc/mobject/builder/buildertool.hpp}}}