Skip to content

Commit e7fcabf

Browse files
committed
doc
1 parent 653cf67 commit e7fcabf

File tree

2 files changed

+143
-17
lines changed

2 files changed

+143
-17
lines changed

.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,13 @@ doc/html/*
1616
.vscode/
1717
.vs/
1818
CMakeSettings.json
19+
20+
_deps/
21+
22+
export/
23+
24+
fetch_and_include/
25+
26+
tmpinst/
27+
28+
CMakeFiles/

doc/openmethod.adoc

Lines changed: 133 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -113,26 +113,26 @@ functions (on the left side) and open-methods (on the right side):
113113
114114
struct Animal {
115115
virtual ~Animal() = default;
116-
virtual void kick(std::ostream&) const = 0;
116+
virtual void poke(std::ostream&) const = 0;
117117
};
118118
119119
struct Cat : Animal {
120-
void kick(std::ostream& os) const override;
120+
void poke(std::ostream& os) const override;
121121
};
122122
123123
struct Dog : Animal {
124-
void kick(std::ostream& os) const override;
124+
void poke(std::ostream& os) const override;
125125
};
126126
127127
128128
129129
130-
void Cat::kick(std::ostream& os) const override {
130+
void Cat::poke(std::ostream& os) const override {
131131
os << "hiss";
132132
}
133133
134134
135-
void Dog::kick(std::ostream& os) const override {
135+
void Dog::poke(std::ostream& os) const override {
136136
os << "bark";
137137
}
138138
@@ -145,8 +145,8 @@ int main() {
145145
Animal&& a = Cat();
146146
Animal&& b = Dog();
147147
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"
150150
151151
return 0;
152152
}
@@ -174,15 +174,15 @@ struct Dog : Animal { <3>
174174
175175
176176
BOOST_OPENMETHOD( <4>
177-
kick, (std::ostream&, virtual_<const Animal&>), void);
177+
poke, (std::ostream&, virtual_<const Animal&>), void);
178178
179179
BOOST_OPENMETHOD_OVERRIDE( <5>
180-
kick, (std::ostream& os, const Cat& cat), void) {
180+
poke, (std::ostream& os, const Cat& cat), void) {
181181
os << "hiss";
182182
}
183183
184184
BOOST_OPENMETHOD_OVERRIDE( <5>
185-
kick, (std::ostream& os, const Dog& dog), void) {
185+
poke, (std::ostream& os, const Dog& dog), void) {
186186
os << "bark";
187187
}
188188
@@ -194,8 +194,8 @@ int main() {
194194
Animal&& a = Cat();
195195
Animal&& b = Dog();
196196
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>
199199
200200
return 0;
201201
}
@@ -208,9 +208,9 @@ int main() {
208208
`boost::openmethod::initialize()`. This is typically needed only in the `main`
209209
translation unit.
210210

211-
<3> `kick` does not appear anywhere in the class definitions.
211+
<3> `poke` does not appear anywhere in the class definitions.
212212

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
214214
`Animal` argument, implicitly passed as `this` to the virtual function, has
215215
become an explicit parameter. Its type is decorated with `virtual_`. It is not
216216
required to be the first parameter. The virtual function's cv-qualifier is now
@@ -224,7 +224,7 @@ relationships. This can be done incrementally.
224224

225225
<7> builds the dispatch tables.
226226

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,
228228
depending on the dynamic type if the virtual argument.
229229

230230
If we break it down, we see that the same information is present in both, only
@@ -267,8 +267,10 @@ not exist.
267267
struct Bulldog : Dog {
268268
};
269269
270+
BOOST_OPENMETHOD_CLASSES(Dog, Bulldog);
271+
270272
BOOST_OPENMETHOD_OVERRIDE(
271-
kick, (std::ostream& os, const Bulldog& dog), void) {
273+
poke, (std::ostream& os, const Bulldog& dog), void) {
272274
next(os, dog); // prints "bark"
273275
os << " and bite";
274276
}
@@ -321,7 +323,121 @@ the method's arguments to the types required by the overrider.
321323

322324
== Advanced Features
323325

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+
----
325441

326442
=== Policies
327443

0 commit comments

Comments
 (0)