1 ////////////////////////////////////////////////////////////////////////////////
2 // The Loki Library
3 // Copyright (c) 2001 by Andrei Alexandrescu
4 // This code accompanies the book:
5 // Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design
6 // Patterns Applied". Copyright (c) 2001. Addison-Wesley.
7 // Permission to use, copy, modify, distribute and sell this software for any
8 // purpose is hereby granted without fee, provided that the above copyright
9 // notice appear in all copies and that both that copyright notice and this
10 // permission notice appear in supporting documentation.
11 // The author or Addison-Welsey Longman make no representations about the
12 // suitability of this software for any purpose. It is provided "as is"
13 // without express or implied warranty.
14 ////////////////////////////////////////////////////////////////////////////////
15
16 // Last update: June 20, 2001
17
18 #ifndef VISITOR_INC_
19 #define VISITOR_INC_
20
21 #include "Typelist.h"
22 #include "HierarchyGenerators.h"
23
24 namespace Loki
25 {
26
27 ////////////////////////////////////////////////////////////////////////////////
28 // class template BaseVisitor
29 // The base class of any Acyclic Visitor
30 ////////////////////////////////////////////////////////////////////////////////
31
32 class BaseVisitor
33 {
34 public:
35 virtual ~BaseVisitor() {}
36 };
37
38 ////////////////////////////////////////////////////////////////////////////////
39 // class template Visitor
40 // The building block of Acyclic Visitor
41 ////////////////////////////////////////////////////////////////////////////////
42
43 template <class T, typename R = void>
44 class Visitor
45 {
46 public:
47 typedef R ReturnType;
48 virtual ReturnType Visit(T&) = 0;
49 };
50
51 ////////////////////////////////////////////////////////////////////////////////
52 // class template Visitor (specialization)
53 // This specialization is not present in the book. It makes it easier to define
54 // Visitors for multiple types in a shot by using a typelist. Example:
55 //
56 // class SomeVisitor :
57 // public BaseVisitor // required
58 // public Visitor<TYPELIST_2(RasterBitmap, Paragraph)>,
59 // public Visitor<Paragraph>
60 // {
61 // public:
62 // void Visit(RasterBitmap&); // visit a RasterBitmap
63 // void Visit(Paragraph &); // visit a Paragraph
64 // };
65 ////////////////////////////////////////////////////////////////////////////////
66
67 template <class Head, class Tail, typename R>
68 class Visitor<Typelist<Head, Tail>, R>
69 : public Visitor<Head, R>, public Visitor<Tail, R>
70 {
71 public:
72 typedef R ReturnType;
73 // using Visitor<Head, R>::Visit;
74 // using Visitor<Tail, R>::Visit;
75 };
76
77 template <class Head, typename R>
78 class Visitor<Typelist<Head, NullType>, R> : public Visitor<Head, R>
79 {
80 public:
81 typedef R ReturnType;
82 using Visitor<Head, R>::Visit;
83 };
84
85 ////////////////////////////////////////////////////////////////////////////////
86 // class template BaseVisitorImpl
87 // Implements non-strict visitation (you can implement only part of the Visit
88 // functions)
89 ////////////////////////////////////////////////////////////////////////////////
90
91 template <class TList, typename R = void> class BaseVisitorImpl;
92
93 template <class Head, class Tail, typename R>
94 class BaseVisitorImpl<Typelist<Head, Tail>, R>
95 : public Visitor<Head, R>
96 , public BaseVisitorImpl<Tail, R>
97 {
98 public:
99 // using BaseVisitorImpl<Tail, R>::Visit;
100
101 virtual R Visit(Head&)
102 { return R(); }
103 };
104
105 template <class Head, typename R>
106 class BaseVisitorImpl<Typelist<Head, NullType>, R>
107 : public Visitor<Head, R>
108 {
109 public:
110 virtual R Visit(Head&)
111 { return R(); }
112 };
113
114 ////////////////////////////////////////////////////////////////////////////////
115 // class template BaseVisitable
116 ////////////////////////////////////////////////////////////////////////////////
117
118 template <typename R, typename Visited>
119 struct DefaultCatchAll
120 {
121 static R OnUnknownVisitor(Visited&, BaseVisitor&)
122 { return R(); }
123 };
124
125 ////////////////////////////////////////////////////////////////////////////////
126 // class template BaseVisitable
127 ////////////////////////////////////////////////////////////////////////////////
128
129 template
130 <
131 typename R = void,
132 template <typename, class> class CatchAll = DefaultCatchAll
133 >
134 class BaseVisitable
135 {
136 public:
137 typedef R ReturnType;
138 virtual ~BaseVisitable() {}
139 virtual ReturnType Accept(BaseVisitor&) = 0;
140
141 protected: // give access only to the hierarchy
142 template <class T>
143 static ReturnType AcceptImpl(T& visited, BaseVisitor& guest)
144 {
145 // Apply the Acyclic Visitor
146 if (Visitor<T>* p = dynamic_cast<Visitor<T>*>(&guest))
147 {
148 return p->Visit(visited);
149 }
150 return CatchAll<R, T>::OnUnknownVisitor(visited, guest);
151 }
152 };
153
154 ////////////////////////////////////////////////////////////////////////////////
155 // macro DEFINE_VISITABLE
156 // Put it in every class that you want to make visitable (in addition to
157 // deriving it from BaseVisitable<R>
158 ////////////////////////////////////////////////////////////////////////////////
159
160 #define DEFINE_VISITABLE() \
161 virtual ReturnType Accept(BaseVisitor& guest) \
162 { return AcceptImpl(*this, guest); }
163
164 ////////////////////////////////////////////////////////////////////////////////
165 // class template CyclicVisitor
166 // Put it in every class that you want to make visitable (in addition to
167 // deriving it from BaseVisitable<R>
168 ////////////////////////////////////////////////////////////////////////////////
169
170 template <typename R, class TList>
171 class CyclicVisitor : public Visitor<TList, R>
172 {
173 public:
174 typedef R ReturnType;
175 // using Visitor<TList, R>::Visit;
176
177 template <class Visited>
178 ReturnType GenericVisit(Visited& host)
179 {
180 Visitor<Visited, ReturnType>& subObj = *this;
181 return subObj.Visit(host);
182 }
183 };
184
185 ////////////////////////////////////////////////////////////////////////////////
186 // macro DEFINE_CYCLIC_VISITABLE
187 // Put it in every class that you want to make visitable by a cyclic visitor
188 ////////////////////////////////////////////////////////////////////////////////
189
190 #define DEFINE_CYCLIC_VISITABLE(SomeVisitor) \
191 virtual SomeVisitor::ReturnType Accept(SomeVisitor& guest) \
192 { return guest.GenericVisit(*this); }
193
194 } // namespace Loki
195
196 ////////////////////////////////////////////////////////////////////////////////
197 // Change log:
198 // March 20: add default argument DefaultCatchAll to BaseVisitable
199 // June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
200 ////////////////////////////////////////////////////////////////////////////////
201
202 #endif // VISITOR_INC_