@@ -50,6 +50,40 @@ struct Visitor : crtp<ConcreteVisitor, Visitor, Base>
50
50
virtual void operator ()(base_type &obj) { obj.accept (actual ()); }
51
51
};
52
52
53
+ /* *
54
+ * This helper class creates a single definition of `virtual void operator()(...)` for one subtype in a class hierarchy,
55
+ * and then recursively inherits from an instantiation of that same helper class for the next subtype in the hierarchy.
56
+ * Eventually, this class transitively inherits from \tparam ConcreteVisitor.
57
+ */
58
+ template <typename ConcreteVisitor, typename Base, typename Class, typename ... Classes>
59
+ struct visitor_method_helper : visitor_method_helper<ConcreteVisitor, Base, Classes...>
60
+ {
61
+ using super = visitor_method_helper<ConcreteVisitor, Base, Classes...>;
62
+ template <typename T> using Const = typename super::template Const<T>;
63
+ using super::operator ();
64
+ virtual void operator ()(Const<Class>&) { }
65
+ };
66
+ /* * This specialization marks the end of the class hierarchy. It inherits from \tparam ConcreteVisitor. */
67
+ template <typename ConcreteVisitor, typename Base, typename Class>
68
+ struct visitor_method_helper <ConcreteVisitor, Base, Class> : Visitor<ConcreteVisitor, Base>
69
+ {
70
+ using super = Visitor<ConcreteVisitor, Base>;
71
+ template <typename T> using Const = typename super::template Const<T>;
72
+ using super::operator ();
73
+ virtual void operator ()(Const<Class>&) { }
74
+ };
75
+
76
+ /* *
77
+ * A helper class to define `virtual` visit methods for all classes in \tparam Hierarchy.
78
+ */
79
+ template <typename ConcreteVisitor, typename Base, typename ... Hierarchy>
80
+ struct VisitorImpl : visitor_method_helper<ConcreteVisitor, Base, Hierarchy...>
81
+ {
82
+ using super = visitor_method_helper<ConcreteVisitor, Base, Hierarchy...>;
83
+ template <typename T> using Const = typename super::template Const<T>;
84
+ using super::operator ();
85
+ };
86
+
53
87
/* * This helper class creates a single override of `operator()` for one subtype in a class hierarchy, and then
54
88
* recursively inherits from an instantiation of that same helper class for the next subtype in the hierarchy. This
55
89
* enables overriding all visit methods of \tparam Visitor. */
@@ -121,22 +155,32 @@ auto visit(Callable &&callable, Base &obj, m::tag<Callable>&& = m::tag<Callable>
121
155
}
122
156
123
157
124
- /* ----- Generate a function similar to `std::visit` to easily implement a visitor for the given base class. ----------*/
158
+ /* *
159
+ * \def M_MAKE_STL_VISITABLE(VISITOR, BASE_CLASS, CLASS_LIST)
160
+ * Defines a function `visit()` to make the class hierarchy STL-style visitable with `VISITOR`.
161
+ *
162
+ * All this must be done with a macro, such that the definition of the visitor class and the `visit()` function reside
163
+ * in the *current* namespace (as chosen by the user of this macro). This enables [*argument-dependent lookup*
164
+ * (ADL)](https://en.cppreference.com/w/cpp/language/adl).
165
+ */
125
166
#define M_MAKE_STL_VISITABLE (VISITOR, BASE_CLASS, CLASS_LIST ) \
126
167
template <typename Callable> \
127
168
auto visit (Callable &&callable, BASE_CLASS &obj, m::tag<VISITOR>&& = m::tag<VISITOR>()) { \
128
169
return m::visit<Callable, VISITOR, BASE_CLASS CLASS_LIST (M_COMMA_PRE)>(std::forward<Callable>(callable), obj); \
129
170
}
130
171
131
- /* ----- Declare a visitor to visit the class hierarchy with the given base class and list of subclasses. -------------*/
132
- #define M_DECLARE_VISIT_METHOD (CLASS ) virtual void operator ()(Const<CLASS>&) { };
172
+ /* *
173
+ * \def M_DECLARE_VISITOR(VISITOR_NAME, BASE_CLASS, CLASS_LIST)
174
+ * Defines a visitor `VISITOR_NAME` to visit the class hierarchy rooted in `BASE_CLASS` and with subclasses
175
+ * `CLASS_LIST`. Also defines a function `visit()` to make the class hierarchy STL-style visitable with `VISITOR_NAME`.
176
+ *
177
+ * All this must be done with a macro, such that the definition of the visitor class and the `visit()` function reside
178
+ * in the *current* namespace (as chosen by the user of this macro). This enables [*argument-dependent lookup*
179
+ * (ADL)](https://en.cppreference.com/w/cpp/language/adl).
180
+ */
133
181
#define M_DECLARE_VISITOR (VISITOR_NAME, BASE_CLASS, CLASS_LIST ) \
134
- struct M_EXPORT VISITOR_NAME : m::detail::Visitor<VISITOR_NAME, BASE_CLASS> \
135
- { \
136
- using super = m::detail::Visitor<VISITOR_NAME, BASE_CLASS>; \
137
- template <typename T> using Const = typename super::Const<T>; \
138
- virtual ~VISITOR_NAME () {} \
139
- void operator ()(BASE_CLASS &obj) { obj.accept (*this ); } \
140
- CLASS_LIST (M_DECLARE_VISIT_METHOD) \
182
+ struct VISITOR_NAME : m::detail::VisitorImpl<VISITOR_NAME, BASE_CLASS CLASS_LIST (M_COMMA_PRE)> { \
183
+ using super = m::detail::VisitorImpl<VISITOR_NAME, BASE_CLASS CLASS_LIST (M_COMMA_PRE)>; \
184
+ using super::operator (); \
141
185
}; \
142
186
M_MAKE_STL_VISITABLE (VISITOR_NAME, BASE_CLASS, CLASS_LIST)
0 commit comments