@@ -113,26 +113,26 @@ functions (on the left side) and open-methods (on the right side):
113
113
114
114
struct Animal {
115
115
virtual ~Animal() = default;
116
- virtual void kick (std::ostream&) const = 0;
116
+ virtual void poke (std::ostream&) const = 0;
117
117
};
118
118
119
119
struct Cat : Animal {
120
- void kick (std::ostream& os) const override;
120
+ void poke (std::ostream& os) const override;
121
121
};
122
122
123
123
struct Dog : Animal {
124
- void kick (std::ostream& os) const override;
124
+ void poke (std::ostream& os) const override;
125
125
};
126
126
127
127
128
128
129
129
130
- void Cat::kick (std::ostream& os) const override {
130
+ void Cat::poke (std::ostream& os) const override {
131
131
os << "hiss";
132
132
}
133
133
134
134
135
- void Dog::kick (std::ostream& os) const override {
135
+ void Dog::poke (std::ostream& os) const override {
136
136
os << "bark";
137
137
}
138
138
@@ -145,8 +145,8 @@ int main() {
145
145
Animal&& a = Cat();
146
146
Animal&& b = Dog();
147
147
148
- a.kick (std::cout); // prints "hiss"
149
- a.kick (std::cout); // prints "bark"
148
+ a.poke (std::cout); // prints "hiss"
149
+ a.poke (std::cout); // prints "bark"
150
150
151
151
return 0;
152
152
}
@@ -174,15 +174,15 @@ struct Dog : Animal { <3>
174
174
175
175
176
176
BOOST_OPENMETHOD( <4>
177
- kick , (std::ostream&, virtual_<const Animal&>), void);
177
+ poke , (std::ostream&, virtual_<const Animal&>), void);
178
178
179
179
BOOST_OPENMETHOD_OVERRIDE( <5>
180
- kick , (std::ostream& os, const Cat& cat), void) {
180
+ poke , (std::ostream& os, const Cat& cat), void) {
181
181
os << "hiss";
182
182
}
183
183
184
184
BOOST_OPENMETHOD_OVERRIDE( <5>
185
- kick , (std::ostream& os, const Dog& dog), void) {
185
+ poke , (std::ostream& os, const Dog& dog), void) {
186
186
os << "bark";
187
187
}
188
188
@@ -194,8 +194,8 @@ int main() {
194
194
Animal&& a = Cat();
195
195
Animal&& b = Dog();
196
196
197
- kick (std::cout, a); // prints "hiss" <8>
198
- kick (std::cout, b); // prints "bark" <8>
197
+ poke (std::cout, a); // prints "hiss" <8>
198
+ poke (std::cout, b); // prints "bark" <8>
199
199
200
200
return 0;
201
201
}
@@ -208,9 +208,9 @@ int main() {
208
208
`boost::openmethod::initialize()`. This is typically needed only in the `main`
209
209
translation unit.
210
210
211
- <3> `kick ` does not appear anywhere in the class definitions.
211
+ <3> `poke ` does not appear anywhere in the class definitions.
212
212
213
- <4> `kick ` is declared outside of the classes. It is a free function. The
213
+ <4> `poke ` is declared outside of the classes. It is a free function. The
214
214
`Animal` argument, implicitly passed as `this` to the virtual function, has
215
215
become an explicit parameter. Its type is decorated with `virtual_`. It is not
216
216
required to be the first parameter. The virtual function's cv-qualifier is now
@@ -224,7 +224,7 @@ relationships. This can be done incrementally.
224
224
225
225
<7> builds the dispatch tables.
226
226
227
- <8> `kick ` is called as a free function. The appropriate override is called,
227
+ <8> `poke ` is called as a free function. The appropriate override is called,
228
228
depending on the dynamic type if the virtual argument.
229
229
230
230
If we break it down, we see that the same information is present in both, only
@@ -267,8 +267,10 @@ not exist.
267
267
struct Bulldog : Dog {
268
268
};
269
269
270
+ BOOST_OPENMETHOD_CLASSES(Dog, Bulldog);
271
+
270
272
BOOST_OPENMETHOD_OVERRIDE(
271
- kick , (std::ostream& os, const Bulldog& dog), void) {
273
+ poke , (std::ostream& os, const Bulldog& dog), void) {
272
274
next(os, dog); // prints "bark"
273
275
os << " and bite";
274
276
}
@@ -321,7 +323,121 @@ the method's arguments to the types required by the overrider.
321
323
322
324
== Advanced Features
323
325
324
- === Core API (Macro-less)
326
+ === Core API
327
+
328
+ OpenMethod provides a public interface that does not require using macros. This
329
+ can be useful in certain situations, for example when combining open methods and
330
+ templates.
331
+
332
+ Here is a rewrite of the Animals example.
333
+
334
+ [source,c++]
335
+ ----
336
+ #include <boost/openmethod/core.hpp>
337
+
338
+ using namespace boost::openmethod;
339
+
340
+ class poke_openmethod;
341
+
342
+ using poke = method<
343
+ poke_openmethod(std::ostream&, virtual_<const Animal&>), void>;
344
+ ----
345
+
346
+ An open-method is implemented as an instance of the `method` template. It takes
347
+ a function signature and a return type.
348
+
349
+ The `poke_openmethod` class acts as the method's identifier: it separates it
350
+ from other methods with the same signature. The exact name does not really
351
+ matter, and the class needs not be defined, only declared. Inventing a class
352
+ name can get tedious, so OpenMethod provides a macro for that:
353
+
354
+ [source,c++]
355
+ ----
356
+ #include <boost/openmethod/macros/name.hpp>
357
+
358
+ class BOOST_OPENMETHOD_NAME(pet);
359
+
360
+ using pet = method<
361
+ BOOST_OPENMETHOD_NAME(pet)(std::ostream&, virtual_<const Animal&>), void>;
362
+ ----
363
+
364
+ NOTE: BOOST_OPENMETHOD and associated macros use `BOOST_OPENMETHOD_NAME` in
365
+ their implementation. This makes it possible to mix the "macro" and "core"
366
+ styles.
367
+
368
+ The method can be called via the nested function object `fn`:
369
+
370
+ [source,c++]
371
+ ----
372
+ poke::fn(std::cout, animal);
373
+ ----
374
+
375
+ Overriders are ordinary functions, added to a method using the nested template
376
+ `override`:
377
+
378
+ [source,c++]
379
+ ----
380
+ auto poke_cat(std::ostream& os, const Cat& cat), void) {
381
+ os << "hiss";
382
+ }
383
+
384
+ static poke::override<poke_cat> override_poke_cat;
385
+ ----
386
+
387
+ If we are using C++26, we can use `_` instead of inventing an identifier. Again, OpenMethod provides a small convenience macro for this:
388
+
389
+ NOTE: `override` can register more than one overrider.
390
+
391
+ [source,c++]
392
+ ----
393
+ #include <boost/openmethod/macros/register.hpp>
394
+
395
+ auto poke_dog(std::ostream& os, const Dog& dog), void) {
396
+ os << "bark";
397
+ }
398
+
399
+ BOOST_OPENMETHOD_REGISTER(poke::override<poke_dog>);
400
+ ----
401
+
402
+ `next` is available from the method's nested `next` template:
403
+
404
+ [source,c++]
405
+ ----
406
+
407
+ auto poke_bulldog(std::ostream& os, const Bulldog& dog), void) {
408
+ poke::next<poke_bulldog>(os, dog);
409
+ os << " and bite";
410
+ }
411
+
412
+ BOOST_OPENMETHOD_REGISTER(poke::override<poke_bulldog>);
413
+ ----
414
+
415
+ Why not call `poke_dog` directly? That may be the right thing to do; however,
416
+ keep in mind that, in a real program, a translation unit is not necessarily
417
+ aware of the overriders added elsewhere - especially in presence of dynamic
418
+ loading.
419
+
420
+ [source,c++]
421
+ ----
422
+ BOOST_OPENMETHOD_CLASSES(Animal, Cat, Dog, Bulldog);
423
+ ----
424
+
425
+ [source,c++]
426
+ ----
427
+
428
+
429
+ int main() {
430
+ boost::openmethod::initialize();
431
+
432
+ Animal&& a = Cat();
433
+ Animal&& b = Dog();
434
+
435
+ poke(std::cout, a); // prints "hiss"
436
+ poke(std::cout, b); // prints "bark"
437
+
438
+ return 0;
439
+ }
440
+ ----
325
441
326
442
=== Policies
327
443
0 commit comments