Skip to content

Commit 397ccb6

Browse files
committed
more multiple dispatch doc
1 parent 4ecde2e commit 397ccb6

6 files changed

Lines changed: 157 additions & 26 deletions

File tree

doc/modules/ROOT/examples/CMakeLists.txt

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,26 @@ if (NOT WIN32)
3030
add_subdirectory(shared_libs)
3131
endif()
3232

33-
file(GLOB subdirs "rolex/*")
34-
35-
foreach (subdir ${subdirs})
36-
string(REGEX REPLACE ".*/" "" subex ${subdir})
37-
file(GLOB cpp_files "${subdir}/*.cpp")
38-
add_executable("rolex_${subex}" ${cpp_files})
39-
target_link_libraries("rolex_${subex}" PUBLIC Boost::openmethod)
40-
add_test(NAME "rolex_${subex}" COMMAND "rolex_${subex}")
41-
add_dependencies(tests "rolex_${subex}")
42-
endforeach()
33+
function(add_step_by_step dir)
34+
set(add_test "")
35+
if(ARGC GREATER 1)
36+
set(add_test "${ARGV1}")
37+
else()
38+
set(add_test "ON")
39+
endif()
40+
file(GLOB subdirs "${dir}/*")
41+
42+
foreach (subdir ${subdirs})
43+
string(REGEX REPLACE ".*/" "" subex ${subdir})
44+
file(GLOB cpp_files "${subdir}/*.cpp")
45+
add_executable("${dir}_${subex}" ${cpp_files})
46+
target_link_libraries("${dir}_${subex}" PUBLIC Boost::openmethod)
47+
if(${add_test})
48+
add_test(NAME "${dir}_${subex}" COMMAND "${dir}_${subex}")
49+
endif()
50+
add_dependencies(tests "${dir}_${subex}")
51+
endforeach()
52+
endfunction()
53+
54+
add_step_by_step(rolex)
55+
add_step_by_step(ambiguities OFF)
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright (c) 2018-2025 Jean-Louis Leroy
2+
// Distributed under the Boost Software License, Version 1.0.
3+
// See accompanying file LICENSE_1_0.txt
4+
// or copy at http://www.boost.org/LICENSE_1_0.txt)
5+
6+
// clang-format off
7+
8+
// tag::content[]
9+
#include <boost/openmethod.hpp>
10+
#include <boost/openmethod/initialize.hpp>
11+
#include <iostream>
12+
13+
struct Matrix { virtual ~Matrix() = default; };
14+
struct DenseMatrix : Matrix {};
15+
struct SparseMatrix : Matrix {};
16+
17+
BOOST_OPENMETHOD_CLASSES(Matrix, DenseMatrix, SparseMatrix);
18+
19+
using boost::openmethod::virtual_ptr;
20+
21+
BOOST_OPENMETHOD(
22+
add, (virtual_ptr<const Matrix>, virtual_ptr<const Matrix>), void);
23+
24+
BOOST_OPENMETHOD_OVERRIDE(
25+
add, (virtual_ptr<const Matrix>, virtual_ptr<const SparseMatrix>), void) {
26+
}
27+
28+
BOOST_OPENMETHOD_OVERRIDE(
29+
add, (virtual_ptr<const SparseMatrix>, virtual_ptr<const Matrix>), void) {
30+
}
31+
32+
int main() {
33+
boost::openmethod::initialize();
34+
35+
SparseMatrix a, b;
36+
add(a, b);
37+
}
38+
// end::content[]
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright (c) 2018-2025 Jean-Louis Leroy
2+
// Distributed under the Boost Software License, Version 1.0.
3+
// See accompanying file LICENSE_1_0.txt
4+
// or copy at http://www.boost.org/LICENSE_1_0.txt)
5+
6+
// clang-format off
7+
8+
#include <boost/openmethod.hpp>
9+
#include <boost/openmethod/initialize.hpp>
10+
#include <iostream>
11+
12+
struct Matrix { virtual ~Matrix() = default; };
13+
struct DenseMatrix : Matrix {};
14+
struct SparseMatrix : Matrix {};
15+
16+
BOOST_OPENMETHOD_CLASSES(Matrix, DenseMatrix, SparseMatrix);
17+
18+
using boost::openmethod::virtual_ptr;
19+
20+
BOOST_OPENMETHOD(
21+
add, (virtual_ptr<const Matrix>, virtual_ptr<const Matrix>), void);
22+
23+
BOOST_OPENMETHOD_OVERRIDE(
24+
add, (virtual_ptr<const Matrix>, virtual_ptr<const SparseMatrix>), void) {
25+
}
26+
27+
BOOST_OPENMETHOD_OVERRIDE(
28+
add, (virtual_ptr<const SparseMatrix>, virtual_ptr<const Matrix>), void) {
29+
}
30+
31+
// tag::content[]
32+
BOOST_OPENMETHOD_OVERRIDE(
33+
add, (virtual_ptr<const SparseMatrix>, virtual_ptr<const SparseMatrix>), void) {
34+
}
35+
// end::content[]
36+
37+
int main() {
38+
boost::openmethod::initialize();
39+
40+
SparseMatrix a, b;
41+
add(a, b);
42+
}

doc/modules/ROOT/examples/rolex/7/main.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,12 @@ struct Public : Expense {};
2727
struct Bus : Public {};
2828
struct Metro : Public {};
2929
struct Taxi : Expense {};
30-
struct Jet : Expense {};
30+
struct PrivateJet : Expense {};
3131
// end::classes[]
3232

3333
BOOST_OPENMETHOD_CLASSES(
34-
Role, Employee, Manager, Founder, Expense, Public, Bus, Metro, Taxi, Jet);
34+
Role, Employee, Manager, Founder, Expense, Public, Bus, Metro, Taxi,
35+
PrivateJet);
3536

3637
// tag::approve[]
3738
using boost::openmethod::virtual_ptr;
@@ -75,7 +76,7 @@ int main() {
7576

7677
Bus bus;
7778
Taxi taxi;
78-
Jet jet;
79+
PrivateJet jet;
7980

8081
std::cout << std::boolalpha;
8182
std::cout << approve(bill, bus, 4.0) << "\n"; // true
Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
:example: ../examples/rolex
1+
:example: ../examples
22

33
## Multiple Dispatch
44

@@ -8,23 +8,60 @@ equally in overrider selection, following the same rules as those governing
88
overload resolution - except that the selection happens at runtime, and takes
99
into account the argument's dynamic types.
1010

11-
Multiple dispatch is occasionally useful, and, when it is needed, it can be
12-
difficult to implement correctly and efficiently by hand. For example, given the following classes:
11+
Multiple dispatch is occasionally useful. When it is needed, it can be difficult
12+
to implement correctly and efficiently by hand. For example, given the following
13+
classes:
1314

1415
[source,c++]
1516
----
16-
include::{example}/7/main.cpp[tag=classes]
17+
include::{example}/rolex/7/main.cpp[tag=classes]
1718
----
1819

19-
We want to implement an `approve` method that determines who can make what kind
20-
of expenses. Employees can take any public transportation; managers can also
21-
take a taxi, for a ride cost up to $100.00; and founders can take any
22-
transportation, including a private jet. This can be expressed like so:
20+
We want to implement a function - `approve` - that determines who can make what
21+
kind of expenses. The rules are:
22+
23+
- By default, an expense is rejected.
24+
25+
- Employees can take any public transportation.
26+
27+
- Managers can also take a taxi, for a ride cost up to $100.
28+
29+
- Founders can take any transportation, including a private jet.
30+
31+
This is a case of multiple dispatch: the outcome depends on two parameters. It
32+
can be implemented as a method with two virtual arguments. The four rules can be
33+
expressed as four overriders:
34+
35+
[source,c++]
36+
----
37+
include::{example}/rolex/7/main.cpp[tag=approve]
38+
----
39+
40+
### Ambiguities
41+
42+
Because `approve` understands inheritance, we don't have to specify an overrider
43+
for every combination (5 role classes x 6 expense classes = 30 combinations).
44+
45+
Just like with overload resolution, ambiguities can arise. Let's look at another
46+
example - matrix addition:
2347

2448
[source,c++]
2549
----
26-
include::{example}/7/main.cpp[tag=approve]
50+
include::{example}/ambiguities/1/main.cpp[tag=content]
2751
----
2852

29-
Note that `approve` takes advantage of inheritance to avoid listing all possible
30-
cases explicitly. This is important, because the number of cases grows
53+
The programs terminates with the following error message:
54+
55+
```
56+
ambiguous
57+
Aborted (core dumped)
58+
```
59+
60+
This is because the call to `add(a, b)` is ambiguous: both overriders are equally
61+
good matches. The solution is to add an overrider for the case where both
62+
arguments are `SparseMatrix`:
63+
64+
[source,c++]
65+
----
66+
include::{example}/ambiguities/2/main.cpp[tag=content]
67+
----

test/test_rolex.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ struct Public : Expense {};
3232
struct Bus : Public {};
3333
struct Metro : Public {};
3434
struct Taxi : Expense {};
35-
struct Jet : Expense {};
35+
struct PrivateJet : Expense {};
3636

3737
BOOST_OPENMETHOD_CLASSES(
38-
Role, Employee, Manager, Founder, Expense, Public, Bus, Metro, Taxi, Jet);
38+
Role, Employee, Manager, Founder, Expense, Public, Bus, Metro, Taxi, PrivateJet);
3939

4040
BOOST_OPENMETHOD(pay, (virtual_ptr<Employee>), double);
4141
BOOST_OPENMETHOD(

0 commit comments

Comments
 (0)