15 Commits

Author SHA1 Message Date
Jean-Louis Leroy
f53122eae8 cmake: fix dlopen example 2025-12-22 23:16:02 -05:00
copilot-swe-agent[bot]
41eaec5bef Fix duplicate "because" typo in basics.adoc
Co-authored-by: jll63 <5083077+jll63@users.noreply.github.com>
2025-12-19 00:31:36 -05:00
Jean-Louis Leroy
5796d3c3ea add semicolons after BOOST_OPENMETHOD_CLASSES in examples 2025-12-18 17:04:17 -05:00
Jean-Louis Leroy
a6337d2f55 remove extra semicolons 2025-12-17 20:12:53 -05:00
Jean-Louis Leroy
02cffffe4f libraries.json: update description 2025-12-17 09:28:07 -05:00
Jean-Louis Leroy
ef48e48235 cmake: fix test and examples options 2025-12-14 14:08:04 -05:00
Jean-Louis Leroy
e0ead3bf71 doc: fix redirection page 2025-12-14 13:24:23 -05:00
Jean-Louis Leroy
764c0b9237 improve documentation 2025-11-29 21:47:09 -05:00
Jean-Louis Leroy
c64960d6c8 meta: add Emulation to categories 2025-11-24 20:49:09 -05:00
Jean-Louis Leroy
48e85546ce improve documentation 2025-11-23 12:21:56 -05:00
Jean-Louis Leroy
8933eb3b4f build_antora.sh: fix base-url patch, use mrdocs generated tagfile 2025-11-23 12:09:34 -05:00
Jean-Louis Leroy
b8da0a1088 do not put initialize in aliases 2025-11-15 17:00:04 -05:00
Jean-Louis Leroy
4d91aab7fd make initialize and finalize symmetric 2025-11-15 17:00:04 -05:00
Jean-Louis Leroy
dac3cf7087 silence codecov in forced instantiation 2025-11-15 16:34:51 -05:00
Jean-Louis Leroy
52fa71306e build_antora.sh: patch base-url with permalink 2025-11-15 15:44:36 -05:00
65 changed files with 665 additions and 1725 deletions

View File

@@ -123,5 +123,5 @@ jobs:
path: doc/html
- name: Deploy to GitHub Pages (jll63)
if: matrix.os == 'ubuntu-latest' && github.repository_owner == 'jll63' && github.ref_name == 'feature/doc'
if: matrix.os == 'ubuntu-latest' && github.repository_owner == 'jll63'
uses: actions/deploy-pages@v4

View File

@@ -37,10 +37,35 @@ set(__ignore__ ${CMAKE_C_COMPILER})
# Options
#
#-------------------------------------------------
option(BOOST_OPENMETHOD_BUILD_TESTS "Build boost::openmethod tests even if BUILD_TESTING is OFF" OFF)
option(BOOST_OPENMETHOD_BUILD_EXAMPLES "Build boost::openmethod examples" ${BOOST_OPENMETHOD_IS_ROOT})
option(BOOST_OPENMETHOD_MRDOCS_BUILD "Build the target for MrDocs: see mrdocs.yml" OFF)
option(BOOST_OPENMETHOD_WARNINGS_AS_ERRORS "Treat warnings as errors" OFF)
option(
BOOST_OPENMETHOD_BUILD_TESTS
"Build boost::openmethod tests even if BUILD_TESTING is OFF"
${BOOST_OPENMETHOD_IS_ROOT})
if (BUILD_TESTING)
set(BOOST_OPENMETHOD_BUILD_TESTS ON)
endif ()
option(
BOOST_OPENMETHOD_BUILD_EXAMPLES
"Build boost::openmethod examples"
${BOOST_OPENMETHOD_IS_ROOT})
option(
BOOST_OPENMETHOD_MRDOCS_BUILD
"Build the target for MrDocs: see mrdocs.yml"
OFF)
option(
BOOST_OPENMETHOD_WARNINGS_AS_ERRORS
"Treat warnings as errors"
OFF)
if (BOOST_OPENMETHOD_BUILD_EXAMPLES AND NOT BOOST_OPENMETHOD_BUILD_TESTS)
message(
WARNING
"BOOST_OPENMETHOD_BUILD_EXAMPLES requires BOOST_OPENMETHOD_BUILD_TESTS. Examples will not be built.")
set(BOOST_OPENMETHOD_BUILD_EXAMPLES OFF)
endif()
# Check if environment variable BOOST_SRC_DIR is set
if (NOT DEFINED BOOST_SRC_DIR AND DEFINED ENV{BOOST_SRC_DIR})
@@ -77,9 +102,9 @@ endforeach ()
if (NOT BOOST_OPENMETHOD_MRDOCS_BUILD)
if (BUILD_TESTING OR BOOST_OPENMETHOD_BUILD_TESTS)
set(BOOST_OPENMETHOD_UNIT_TEST_LIBRARIES test)
endif()
if (BOOST_OPENMETHOD_BUILD_EXAMPLES)
set(BOOST_OPENMETHOD_EXAMPLE_LIBRARIES dll)
if (BOOST_OPENMETHOD_BUILD_EXAMPLES)
set(BOOST_OPENMETHOD_EXAMPLE_LIBRARIES dll)
endif()
endif()
endif()
# Complete dependency list
@@ -175,20 +200,15 @@ endif()
# Tests
#
#-------------------------------------------------
if (BUILD_TESTING OR BOOST_OPENMETHOD_BUILD_TESTS)
if (BOOST_OPENMETHOD_BUILD_TESTS)
enable_testing()
add_subdirectory(test)
if (BOOST_OPENMETHOD_IS_ROOT)
add_custom_target(all_with_tests ALL DEPENDS tests)
endif()
endif ()
#-------------------------------------------------
#
# Examples
#
#-------------------------------------------------
if (BOOST_OPENMETHOD_BUILD_EXAMPLES)
enable_testing()
add_subdirectory(doc/modules/ROOT/examples)
# Examples
if (BOOST_OPENMETHOD_BUILD_EXAMPLES)
add_subdirectory(doc/modules/ROOT/examples)
endif ()
endif ()

View File

@@ -21,11 +21,6 @@ ext:
cpp-reference:
config: doc/mrdocs.yml
cpp-tagfiles:
files:
- file: ./doc/tagfiles/boost-openmethod-doxygen.tag.xml
base_url: 'xref:reference:'
- file: ./doc/tagfiles/boost-openmethod-macros-doxygen.tag.xml
base_url: 'xref:reference:'
using-namespaces:
- boost::openmethod
- boost::openmethod::policies

View File

@@ -6,7 +6,7 @@
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#
# Official repository: https://github.com/boostorg/openmethod
# Official REPOSITORY: https://github.com/boostorg/openmethod
#
set -e
@@ -22,6 +22,52 @@ fi
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
cd "$SCRIPT_DIR"
if [ -z "${BOOST_SRC_DIR:-}" ]; then
CANDIDATE=$( cd "$SCRIPT_DIR/../../.." 2>/dev/null && pwd )
if [ -n "$CANDIDATE" ]; then
BOOST_SRC_DIR_IS_VALID=ON
for F in "CMakeLists.txt" "Jamroot" "boost-build.jam" "bootstrap.sh" "libs"; do
if [ ! -e "$CANDIDATE/$F" ]; then
BOOST_SRC_DIR_IS_VALID=OFF
break
fi
done
if [ "$BOOST_SRC_DIR_IS_VALID" = "ON" ]; then
export BOOST_SRC_DIR="$CANDIDATE"
echo "Using BOOST_SRC_DIR=$BOOST_SRC_DIR"
fi
fi
fi
if [ -n "${BOOST_SRC_DIR:-}" ]; then
if [ -n "${CIRCLE_REPOSITORY_URL:-}" ]; then
if [[ "$CIRCLE_REPOSITORY_URL" =~ boostorg/boost(\.git)?$ ]]; then
LIB="$(basename "$(dirname "$SCRIPT_DIR")")"
REPOSITORY="boostorg/${LIB}"
else
ACCOUNT="${CIRCLE_REPOSITORY_URL#*:}"
ACCOUNT="${ACCOUNT%%/*}"
LIB=$(basename "$(git rev-parse --show-toplevel)")
REPOSITORY="${ACCOUNT}/${LIB}"
fi
SHA=$(git -C "$BOOST_SRC_DIR/libs" ls-tree HEAD | grep -w openmethod | awk '{print $3}')
elif [ -n "${GITHUB_REPOSITORY:-}" ]; then
REPOSITORY="${GITHUB_REPOSITORY}"
SHA="${GITHUB_SHA}"
fi
fi
cd "$SCRIPT_DIR"
if [ -n "${REPOSITORY}" ] && [ -n "${SHA}" ]; then
base_url="https://github.com/${REPOSITORY}/blob/${SHA}"
echo "Setting base-url to $base_url"
cp mrdocs.yml mrdocs.yml.bak
perl -i -pe 's{^\s*base-url:.*$}{base-url: '"$base_url/"'}' mrdocs.yml
else
echo "REPOSITORY or SHA not set; skipping base-url modification"
fi
echo "Building documentation with Antora..."
echo "Installing npm dependencies..."
npm ci
@@ -29,7 +75,7 @@ npm ci
echo "Building docs in custom dir..."
PATH="$(pwd)/node_modules/.bin:${PATH}"
export PATH
npx antora --clean --fetch "$PLAYBOOK" --stacktrace --log-level all
npx antora --clean --fetch "$PLAYBOOK" --stacktrace # --log-level all
echo "Fixing links to non-mrdocs URIs..."
@@ -37,4 +83,15 @@ for f in $(find html -name '*.html'); do
perl -i -pe 's{&lcub;&lcub;(.*?)&rcub;&rcub;}{<a href="../../../$1.html">$1</a>}g' "$f"
done
if [ -n "${base_url:-}" ]; then
if [ -f mrdocs.yml.bak ]; then
mv -f mrdocs.yml.bak mrdocs.yml
echo "Restored original mrdocs.yml"
else
echo "mrdocs.yml.bak not found; skipping restore"
fi
perl -i -pe "s[{{BASE_URL}}][$base_url]g" \
html/openmethod/ref_headers.html html/openmethod/BOOST_OPENMETHOD*.html
fi
echo "Done"

View File

@@ -1,67 +0,0 @@
# Introduction
Open-methods are similar to virtual functions, but they are not required to be
members of a class. By being both free and virtual, they provide a solution to
the Expression Problem:
> Given a set of types, and a set of operations on these types, is it possible
to add new operations on the existing types, and new types to the existing
operations, without modifying existing code?
Open-methods also address the banana-gorilla-shared problem:
> The problem with object-oriented languages is theyve got all this implicit
environment that they carry around with them. You wanted a banana but what you
got was a gorilla holding the banana and the entire shared. — Joe Armstrong,
creator of Erlang progamming language
As a bonus, open-methods can take more than one argument into account when
selecting the appropriate function to call - aka multiple dispatch. For that
reason, open-methods are often called multi-methods, but that term is
misleading, as it suggests that the feature is useful only when multiple
dispatch is needed. In reality,
https://openaccess.wgtn.ac.nz/articles/thesis/Multiple_Dispatch_in_Practice/16959112/1[it
has been observed] that, in large systems written in languages that support
multi-methods, most methods use single-dispatch. The real benefit is in the
solution to the Expression Problem.
Open-methods were introduced by the Common Lisp Object System, and they are
native to many languages: Clojure, Julia, Dylan, TADS, Cecil, Diesel, Nice, etc.
Bjarne Stroustrup wanted open-methods in C++ almost from the beginning. In D&E
he writes:
> I repeatedly considered a mechanism for a virtual function call based on more
than one object, often called multi-methods. I rejected multi-methods with
regret because I liked the idea, but couldnt find an acceptable form under
which to accept it. [...] Multi-methods is one of the interesting what-ifs of
C++. Could I have designed and implemented them well enough at the time? Would
their applications have been important enough to warrant the effort? What other
work might have been left undone to provide the time to design and implement
multi-methods? Since about 1985, I have always felt some twinge of regret for
not providing multi-methods (Stroustrup, 1994, The Design and Evolution of
C{plus}{plus}, 13.8).
Circa 2007, he and his PhD students Peter Pirkelbauer and Yuriy Solodkyy wrote a
series of papers and a prototype implementation based on the EDG compiler.
Unfortunately, open-methods never made it into the standard. Stroustrup bemoans,
in a more recent paper:
> In retrospect, I dont think that the object-oriented notation (e.g., x.f(y))
should ever have been introduced. The traditional mathematical notation f(x,y)
is sufficient. As a side benefit, the mathematical notation would naturally have
given us multi-methods, thereby saving us from the visitor pattern workaround
(Stroustrup, 2020, Thriving in a Crowded and ChangingWorld: C++ 20062020).
This library implements the features described in the
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2216.pdf[N2216 paper],
with some extensions:
* a mechanism for calling the next most specialized overrider
* support for smart pointers
* customization points for RTTI, error handling, tracing, smart pointers...
Multiple and virtual inheritance are supported, with the exception of repeated
inheritance.

View File

@@ -14,5 +14,5 @@ BOOST_OPENMETHOD_OVERRIDE(
return 5000.0;
}
BOOST_OPENMETHOD_CLASSES(Employee)
BOOST_OPENMETHOD_CLASSES(Employee);
// end::content[]

View File

@@ -14,6 +14,6 @@ BOOST_OPENMETHOD_OVERRIDE(
return next(emp) + emp->sales * 0.05; // base + commission
}
BOOST_OPENMETHOD_CLASSES(Employee, Salesman)
BOOST_OPENMETHOD_CLASSES(Employee, Salesman);
// end::content[]

View File

@@ -12,5 +12,5 @@ BOOST_OPENMETHOD_DEFINE_OVERRIDER(
return 5000.0;
}
BOOST_OPENMETHOD_CLASSES(Employee)
BOOST_OPENMETHOD_CLASSES(Employee);
// end::content[]

View File

@@ -16,4 +16,4 @@ BOOST_OPENMETHOD_OVERRIDE(
}
// end::content[]
BOOST_OPENMETHOD_CLASSES(Employee, Salesman)
BOOST_OPENMETHOD_CLASSES(Employee, Salesman);

View File

@@ -7,5 +7,5 @@
#include "roles.hpp"
#include <boost/openmethod.hpp>
BOOST_OPENMETHOD_CLASSES(Employee)
BOOST_OPENMETHOD_CLASSES(Employee);
// end::content[]

View File

@@ -16,4 +16,4 @@ BOOST_OPENMETHOD_OVERRIDE(
}
// end::content[]
BOOST_OPENMETHOD_CLASSES(Employee, Salesman)
BOOST_OPENMETHOD_CLASSES(Employee, Salesman);

View File

@@ -7,5 +7,5 @@
#include "roles.hpp"
#include <boost/openmethod.hpp>
BOOST_OPENMETHOD_CLASSES(employees::Employee)
BOOST_OPENMETHOD_CLASSES(employees::Employee);
// end::content[]

View File

@@ -17,7 +17,7 @@ BOOST_OPENMETHOD_OVERRIDE(
emp->sales * 0.05; // base + commission
}
BOOST_OPENMETHOD_CLASSES(employees::Employee, Salesman)
BOOST_OPENMETHOD_CLASSES(employees::Employee, Salesman);
} // namespace sales
// end::content[]

View File

@@ -71,7 +71,7 @@ BOOST_OPENMETHOD_OVERRIDE(
}
// ...and let's not forget to register the classes
BOOST_OPENMETHOD_CLASSES(Employee, Salesman)
BOOST_OPENMETHOD_CLASSES(Employee, Salesman);
// end::overriders[]
// tag::main[]

View File

@@ -66,7 +66,7 @@ BOOST_OPENMETHOD_OVERRIDE(
}
// ...and let's not forget to register the classes
BOOST_OPENMETHOD_CLASSES(Employee, Salesman)
BOOST_OPENMETHOD_CLASSES(Employee, Salesman);
// end::overriders[]
// tag::main[]

View File

@@ -12,7 +12,10 @@ add_compile_definitions(BOOST_OPENMETHOD_ENABLE_RUNTIME_CHECKS)
add_library(boost_openmethod-shared SHARED extensions.cpp)
target_link_libraries(boost_openmethod-shared Boost::openmethod)
set_target_properties(boost_openmethod-shared PROPERTIES ENABLE_EXPORTS ON)
set_target_properties(boost_openmethod-shared PROPERTIES
ENABLE_EXPORTS ON
OUTPUT_NAME shared
)
add_executable(boost_openmethod-static static_main.cpp)
target_link_libraries(boost_openmethod-static Boost::openmethod Boost::dll boost_openmethod-shared)
@@ -36,7 +39,10 @@ add_library(boost_openmethod-indirect_shared SHARED indirect_extensions.cpp)
target_compile_definitions(
boost_openmethod-indirect_shared PUBLIC BOOST_OPENMETHOD_DEFAULT_REGISTRY=indirect_registry)
target_link_libraries(boost_openmethod-indirect_shared PRIVATE Boost::openmethod Boost::dll)
set_target_properties(boost_openmethod-indirect_shared PROPERTIES ENABLE_EXPORTS ON)
set_target_properties(boost_openmethod-indirect_shared PROPERTIES
ENABLE_EXPORTS ON
OUTPUT_NAME indirect_shared
)
add_executable(boost_openmethod-indirect indirect_main.cpp)
target_compile_definitions(

View File

@@ -41,7 +41,7 @@ int main() {
// end::unload[]
std::cout << "Before loading the shared library.\n";
initialize();
boost::openmethod::initialize();
std::cout << "cow meets wolf -> "
<< meet(*std::make_unique<Cow>(), *std::make_unique<Wolf>())
@@ -60,7 +60,7 @@ int main() {
boost::dll::shared_library lib(
boost::dll::program_location().parent_path() / LIBRARY_NAME,
boost::dll::load_mode::rtld_now);
initialize();
boost::openmethod::initialize();
std::cout << "cow meets wolf -> "
<< meet(*std::make_unique<Cow>(), *std::make_unique<Wolf>())
@@ -83,7 +83,7 @@ int main() {
std::cout << "\nAfter unloading the shared library.\n";
lib.unload();
initialize();
boost::openmethod::initialize();
std::cout << "cow meets wolf -> "
<< meet(*std::make_unique<Cow>(), *std::make_unique<Wolf>())

View File

@@ -37,7 +37,7 @@ auto main() -> int {
using namespace boost::openmethod::aliases;
std::cout << "Before loading the shared library.\n";
initialize();
boost::openmethod::initialize();
auto gracie = make_unique_virtual<Cow>();
auto willy = make_unique_virtual<Wolf>();
@@ -53,7 +53,7 @@ auto main() -> int {
boost::dll::program_location().parent_path() / LIBRARY_NAME,
boost::dll::load_mode::rtld_now);
initialize();
boost::openmethod::initialize();
std::cout << "cow meets wolf -> " << meet(*gracie, *willy) << "\n"; // run
std::cout << "wolf meets cow -> " << meet(*willy, *gracie) << "\n"; // hunt

View File

@@ -30,7 +30,7 @@ auto make_tiger() -> Animal*;
}
auto main() -> int {
initialize();
boost::openmethod::initialize();
std::unique_ptr<Animal> gracie(new Cow());
std::unique_ptr<Animal> willy(new Wolf());

View File

@@ -22,7 +22,7 @@ struct Node {
struct Variable : Node {
Variable(int value) : v(value) {
vptr = boost::openmethod::default_registry::static_vptr<Variable>;
vptr = registry::static_vptr<Variable>;
}
int v;
@@ -30,7 +30,7 @@ struct Variable : Node {
struct Plus : Node {
Plus(const Node& left, const Node& right) : left(left), right(right) {
vptr = boost::openmethod::default_registry::static_vptr<Plus>;
vptr = registry::static_vptr<Plus>;
}
const Node& left;
@@ -39,7 +39,7 @@ struct Plus : Node {
struct Times : Node {
Times(const Node& left, const Node& right) : left(left), right(right) {
vptr = boost::openmethod::default_registry::static_vptr<Times>;
vptr = registry::static_vptr<Times>;
}
const Node& left;

View File

@@ -1,11 +1,12 @@
* xref:introduction.adoc[Introduction]
* xref:basics.adoc[Open-Methods 101]
* xref:performance.adoc[Performance]
* xref:smart_pointers.adoc[Smart Pointers]
* xref:headers.adoc[Headers]
* xref:namespaces.adoc[Namespaces]
* xref:friendship.adoc[Friendship]
* xref:multiple_dispatch.adoc[Multiple Dispatch]
* xref:motivation.adoc[Motivation]
* Basic Features
** xref:basics.adoc[Methods and Overriders]
** xref:performance.adoc[Performance]
** xref:smart_pointers.adoc[Smart Pointers]
** xref:headers.adoc[Header and Implementation Files]
** xref:namespaces.adoc[Namespaces]
** xref:friends.adoc[Friends]
** xref:multiple_dispatch.adoc[Multiple Dispatch]
* Advanced Features
** xref:core_api.adoc[Core API]
** xref:registries_and_policies.adoc[Registries and Policies]

View File

@@ -1,15 +1,15 @@
= BOOST_OPENMETHOD
# BOOST_OPENMETHOD
### Synopsis
## Synopsis
Defined in <boost/openmethod/macros.hpp>.
Defined in link:{{BASE_URL}}/include/boost/openmethod/macros.hpp[<boost/openmethod/macros.hpp>].
```c++
BOOST_OPENMETHOD(ID, (PARAMETERS...), RETURN_TYPE [, REGISTRY]);
```
### Description
## Description
Declares a method, called `ID`, with the given `PARAMETERS` and `RETURN_TYPE`,
and adds it to `REGISTRY`.
@@ -58,7 +58,7 @@ NOTE: The default value for `REGISTRY` is the value of
`BOOST_OPENMETHOD_DEFAULT_REGISTRY` at the point `<boost/openmethod/core.hpp>` is
included. Changing the value of this symbol has no effect after that point.
### Implementation Notes
## Implementation Notes
The macro creates several additional constructs:

View File

@@ -1,17 +1,14 @@
# BOOST_OPENMETHOD_CLASSES
[#BOOST_OPENMETHOD_CLASSES]
## Synopsis
## BOOST_OPENMETHOD_CLASSES
### Synopsis
Defined in <boost/openmethod/macros.hpp>.
Defined in link:{{BASE_URL}}/include/boost/openmethod/macros.hpp[<boost/openmethod/macros.hpp>].
```c++
BOOST_OPENMETHOD_CLASSES(CLASSES...[, REGISTRY]);
```
### Description
## Description
Registers `CLASSES` in REGISTRY.

View File

@@ -1,15 +1,14 @@
# BOOST_OPENMETHOD_DECLARE_OVERRIDER
## BOOST_OPENMETHOD_DECLARE_OVERRIDER
## Synopsis
### Synopsis
Defined in <boost/openmethod/macros.hpp>.
Defined in link:{{BASE_URL}}/include/boost/openmethod/macros.hpp[<boost/openmethod/macros.hpp>].
```c++
#define BOOST_OPENMETHOD_DECLARE_OVERRIDER(NAME, (PARAMETERS...), RETURN_TYPE)
```
### Description
## Description
Declares an overrider for a method, but does not start its definition. This
macro can be used in header files.
@@ -33,7 +32,7 @@ Each `virtual_<T>` in the method's parameter list must have a corresponding `U`
parameter in the same position in the overrider's parameter list, such that `U`
is the same as `T`, or has `T` as an accessible unambiguous base.
### Implementation Notes
## Implementation Notes
The macro creates additional entities in the current scope.

View File

@@ -1,4 +1,4 @@
= xref:macros.adoc[Macro]&nbsp;BOOST_OPENMETHOD_DEFAULT_REGISTRY
# BOOST_OPENMETHOD_DEFAULT_REGISTRY
Default value for Registry

View File

@@ -1,15 +1,15 @@
## BOOST_OPENMETHOD_DEFINE_OVERRIDER
# BOOST_OPENMETHOD_DEFINE_OVERRIDER
### Synopsis
## Synopsis
Defined in <boost/openmethod/macros.hpp>.
Defined in link:{{BASE_URL}}/include/boost/openmethod/macros.hpp[<boost/openmethod/macros.hpp>].
```c++
#define BOOST_OPENMETHOD_DEFINE_OVERRIDER(ID, (PARAMETERS...), RETURN_TYPE)
```
### Description
## Description
Defines the body of an overrider declared with
xref:BOOST_OPENMETHOD_DECLARE_OVERRIDER.adoc[BOOST_OPENMETHOD_DECLARE_OVERRIDER].

View File

@@ -1,13 +1,13 @@
## BOOST_OPENMETHOD_ENABLE_RUNTIME_CHECKS
# BOOST_OPENMETHOD_ENABLE_RUNTIME_CHECKS
Enables runtime checks in cpp:default_registry[].
### Synopsis
## Synopsis
May be defined by a program before including
`<boost/openmethod/default_registry.hpp>` to enable runtime checks.
### Description
## Description
See cpp:default_registry[] for details.

View File

@@ -1,17 +1,15 @@
[#BOOST_OPENMETHOD_ID]
# BOOST_OPENMETHOD_ID
## BOOST_OPENMETHOD_ID
## Synopsis
### Synopsis
Defined in <boost/openmethod/macros.hpp>.
Defined in link:{{BASE_URL}}/include/boost/openmethod/macros.hpp[<boost/openmethod/macros.hpp>].
```c++
#define BOOST_OPENMETHOD_ID(ID) /* unspecified */
```
### Description
## Description
Generates a long, obfuscated name from a short name. All the other names
generated by macros are based on this name.

View File

@@ -1,11 +1,8 @@
# BOOST_OPENMETHOD_INLINE_OVERRIDE
[#BOOST_OPENMETHOD_INLINE_OVERRIDE]
## Synopsis
## BOOST_OPENMETHOD_INLINE_OVERRIDE
### Synopsis
Defined in <boost/openmethod/macros.hpp>.
Defined in link:{{BASE_URL}}/include/boost/openmethod/macros.hpp[<boost/openmethod/macros.hpp>].
```c++
BOOST_OPENMETHOD_INLINE_OVERRIDE(ID, (PARAMETERS...), RETURN_TYPE) {
@@ -13,7 +10,7 @@ BOOST_OPENMETHOD_INLINE_OVERRIDE(ID, (PARAMETERS...), RETURN_TYPE) {
}
```
### Description
## Description
`BOOST_OPENMETHOD_INLINE_OVERRIDE` performs the same function as
xref:BOOST_OPENMETHOD_OVERRIDE.adoc[BOOST_OPENMETHOD_OVERRIDE], except that the

View File

@@ -1,11 +1,9 @@
[#BOOST_OPENMETHOD_OVERRIDE]
# BOOST_OPENMETHOD_OVERRIDE
## BOOST_OPENMETHOD_OVERRIDE
## Synopsis
### Synopsis
Defined in <boost/openmethod/macros.hpp>.
Defined in link:{{BASE_URL}}/include/boost/openmethod/macros.hpp[<boost/openmethod/macros.hpp>].
```c++
BOOST_OPENMETHOD_OVERRIDE(ID, (PARAMETERS...), RETURN_TYPE) {
@@ -13,7 +11,7 @@ BOOST_OPENMETHOD_OVERRIDE(ID, (PARAMETERS...), RETURN_TYPE) {
}
```
### Description
## Description
`BOOST_OPENMETHOD_OVERRIDE` adds an overrider to a method.
@@ -48,7 +46,7 @@ and terminates the program.
* `has_next()`: returns `true` if the next most specialized overrider exists.
### Implementation Notes
## Implementation Notes
The macro creates additional entities in the current scope.

View File

@@ -1,15 +1,15 @@
## BOOST_OPENMETHOD_OVERRIDER
# BOOST_OPENMETHOD_OVERRIDER
### Synopsis
## Synopsis
Defined in <boost/openmethod/macros.hpp>.
Defined in link:{{BASE_URL}}/include/boost/openmethod/macros.hpp[<boost/openmethod/macros.hpp>].
```c++
#define BOOST_OPENMETHOD_OVERRIDER(ID, (PARAMETERS...), RETURN_TYPE)
```
### Description
## Description
Expands to the specialization of the class template that contains the overrider
for with the given name, parameter list and return type.

View File

@@ -1,16 +1,16 @@
## BOOST_OPENMETHOD_OVERRIDERS
# BOOST_OPENMETHOD_OVERRIDERS
### Synopsis
## Synopsis
Defined in <boost/openmethod/macros.hpp>.
Defined in link:{{BASE_URL}}/include/boost/openmethod/macros.hpp[<boost/openmethod/macros.hpp>].
```c++
#define BOOST_OPENMETHOD_OVERRIDERS(ID) \
BOOST_PP_CAT(BOOST_OPENMETHOD_ID(ID), _overriders)
```
### Description
## Description
`BOOST_OPENMETHOD_OVERRIDERS` expands to the name of the class template that
contains the overriders for all the methods with a given name.

View File

@@ -1,17 +1,15 @@
[#BOOST_OPENMETHOD_REGISTER]
# BOOST_OPENMETHOD_REGISTER
## BOOST_OPENMETHOD_REGISTER
## Synopsis
### Synopsis
Defined in <boost/openmethod/macros.hpp>.
Defined in link:{{BASE_URL}}/include/boost/openmethod/macros.hpp[<boost/openmethod/macros.hpp>].
```c++
BOOST_OPENMETHOD_REGISTER(TYPE);
```
### Description
## Description
Creates a registrar for `TYPE`, i.e. a static `TYPE` object with a unique
generated name. At static initialization time, the object adds itself to a list:

View File

@@ -1,15 +1,14 @@
# BOOST_OPENMETHOD_TYPE
= BOOST_OPENMETHOD_TYPE
## Synopsis
### Synopsis
Defined in <boost/openmethod/macros.hpp>.
Defined in link:{{BASE_URL}}/include/boost/openmethod/macros.hpp[<boost/openmethod/macros.hpp>].
```c++
BOOST_OPENMETHOD_TYPE(ID, (PARAMETERS...), RETURN_TYPE [, REGISTRY]);
```
### Description
## Description
Expands to the core cpp:method[`method`] specialization created by
xref:BOOST_OPENMETHOD.adoc[BOOST_OPENMETHOD] called with the same arguments.

View File

@@ -1,12 +1,12 @@
:exampledir: ../example
## Open-Methods 101
[#basics]
An _open-method_ is a free-standing function that takes one or more _virtual_
An _open-method_ is a free-standing function that has one or more _virtual_
_parameters_. When it is called, it forwards to an _overrider_ selected from a
set by examining the dynamic types of the virtual parameters.
If this sounds like a virtual function, that's because because an open-method
If this sounds like a virtual function, that's because an open-method
with one virtual parameter is equivalent to a virtual function - with one big
difference: it exists outside of classes.
@@ -22,7 +22,7 @@ BOOST_OPENMETHOD(
postfix, (virtual_ptr<const Node> node, std::ostream& os), void);
```
This method is called `postfix`. It takes one virtual parameter, `node`, and one
`postfix` is the method's name. It takes one virtual parameter, `node`, and one
non-virtual parameter, `os`. It returns `void`. The macro generates the
following function:
@@ -61,15 +61,15 @@ This one calls `postfix` recursively to print the left and right
sub-expressions. Note that we call the method just like an ordinary function.
`postfix` expects a `virtual_ptr<const Node>`, and we are passing it a _plain_
_reference_ to a `Plus` object. This works because `virtual_ptr` has conversion
constructors from plain references or pointers to an object, or from other
`virtual_ptr`{empty}s to compatible classes.
_reference_ to a `Node` object. This works because `virtual_ptr` has conversion
constructors from plain references or pointers to objects, or from other
`virtual_ptr`{empty}s.
There are two more things we need to do.
OpenMethod is a library, not a compiler. It needs to be made aware of all the
OpenMethod is a library, not a compiler. It needs to be informed of all the
classes that may be used as virtual parameters, and in method calls, and their
inheritance relationships. We do this with the
inheritance relationships. We provide that information with the
xref:BOOST_OPENMETHOD_CLASSES.adoc[BOOST_OPENMETHOD_CLASSES] macro:
@@ -84,8 +84,8 @@ direct base of a class must appear together with it in at least one call to
inheritance lattice.
The constructs used in this example require the classes to be polymorphic, in
the standard C++ sense, i.e. have at least one virtual function. The library can
also be used with non-polymorphic classes, with some restrictions.
the standard C++ sense, i.e. they must have at least one virtual function. The
library can also be used with non-polymorphic classes, with some restrictions.
Finally, we need to call `boost::openmethod::initialize()` before the first call
to an open-method. This builds the dispatch tables used during method calls. It

View File

@@ -1,6 +1,6 @@
:example: ../examples/core_api/1
## Core API
[#core_api]
OpenMethod provides a macro-free interface: the core API. This is useful in
certain situations, for example when combining open-methods and templates.
@@ -25,8 +25,8 @@ method, `prefix`, which writes expressions in prefix notation. It would have the
same signature. Without the identifier argument, `prefix` and `postfix` would be the
same method.
The exact name of the identifier class does not matter, as long as it is unique enough.
The class needs not be defined, only declared.
The exact name of the identifier class does not matter. The class needs not be
defined, only declared.
Inventing identifier class names can get tedious, so OpenMethod provides a macro
for that: xref:BOOST_OPENMETHOD_ID.adoc[BOOST_OPENMETHOD_ID]. Let's use it:
@@ -58,9 +58,12 @@ functions passed as template arguments to the method.
include::{example}/core_api.cpp[tag=variable_overrider]
----
Once again we find ourselves inventing a name that will not be used again. In
C++26, we will probably have the Python-like `_` for this. In the meantime, we
can use a small macro:
Once again we find ourselves inventing a name for a single use. In C++26, we
will probably have the Python-like `_` for this.
We can also use a small macro:
xref:BOOST_OPENMETHOD_REGISTER.adoc[BOOST_OPENMETHOD_REGISTER]. It takes a
class, and instantiates a static object with an obfuscated name:
[source,c++]
----
@@ -91,7 +94,7 @@ The primary purpose of the core API is to make open-methods inter-operate with
templates.
`Plus` and `Times` are obvious candidates for templatization. They only differ
by the operation they perform, and we already have templates fore that in the
by the operation they perform, and we already have templates for that in the
standard library:
[source,c++]
@@ -118,8 +121,8 @@ include::{example}/core_api.cpp[tag=postfix_binary]
----
Macro xref:BOOST_OPENMETHOD_TYPE.adoc[BOOST_OPENMETHOD_TYPE] takes the same
parameters as `BOOST_OPENMETHOD`, and expands to the core method type. That is
how we access its nested `overrider` class template:
parameters as `BOOST_OPENMETHOD`, and expands to the core cpp:method[method]
instance. That is how we access its nested `overrider` class template:
[source,c++]
----

View File

@@ -1,7 +1,7 @@
:example: ../examples/custom_rtti
## Custom RTTI
[#custom_rtti]
The original motivation for the policy mechanism is to make it possible to
interface OpenMethod with custom RTTI systems.
@@ -106,25 +106,26 @@ still work.
The policy is quite minimal. It does not support virtual inheritance, because it
does not provide a `dynamic_cast_ref` function. It would not produce good error
or trace messages, because it does not provide a `type_name` function. Instead,
it relies on the `type_name` inherited from `rtti::default`. It renders types as
adorned integers, e.g. "type_id(2)". All non-"polymorphic" types would be
rendered the same way, as "type_id(0)".
it relies on the `type_name` inherited from cpp:rtti::defaults[]. It
renders types as adorned integers, e.g. "type_id(2)". All non-"polymorphic"
types would be rendered the same way, as "type_id(0)".
`rtti::default` also provides a default implementation for `type_index`, which
simply returns its argument.
cpp:rtti::defaults[] also provides a default implementation for `type_index`,
which simply returns its argument.
Now we need a policy to get a v-table pointer from an object. Our RTTI system
has an interesting property: its type ids are monotonically allocated in a
small, dense range. It means that we can use them as straight indexes in a
vector. `vptr_vector` is perfect for that. So here is our registry:
small, dense range. It means that we can use them as indexes in a vector.
`vptr_vector` is perfect for that. So here is our registry:
[source,c++]
----
include::{example}/1/custom_rtti.cpp[tag=registry]
----
Defining macro `BOOST_OPENMETHOD_DEFAULT_REGISTRY` sets the default registry
used by all library components that need one.
Defining macro
xref:BOOST_OPENMETHOD_DEFAULT_REGISTRY.adoc[BOOST_OPENMETHOD_DEFAULT_REGISTRY]
sets the default registry used by all library components that need one.
Next, we include the main header.
Because `BOOST_OPENMETHOD_DEFAULT_REGISTRY` is defined, its value is used

View File

@@ -1,15 +1,14 @@
## Error Handling
[#error_handling]
Errors can occur during `initialize`, or during method dispatch, if the
method's registry contains the `runtime_checks` policy. If the registry
contains an `error_handler` policy, its `error_handler::error` member
function is called with a variant containing an error object, before terminating
the program with a call to `abort`. `default_registry` contains such a
policy: `default_error_handler`. It wraps the error object in a variant, and
calls a handler via a `std::function`. By default, it prints a short description
of the error to `stderr`, but this can be changed, for example, to throw an
exception:
Errors can occur during `initialize`, or during method dispatch, if the method's
registry contains the `runtime_checks` policy. If the registry contains an
`error_handler` policy, its `error_handler::error` member function is called
with an error object, before terminating the program with a call to `abort`.
`default_registry` contains such a policy: `default_error_handler`. It wraps the
error object in a variant, and calls a handler via a `std::function`,
initialized to a function that prints a short description of the error to
`stderr`. The function can be changed, for example, to throw an exception:
[source,c++]
----
@@ -43,11 +42,14 @@ spin
Stock policy `throw_error_handler` does this for all the error types:
```c++ namespace boost::openmethod::policies {
```c++
namespace boost::openmethod::policies {
struct throw_error_handler : error_handler { template<class Error>
[[noreturn]] static auto error(const Error& error) -> void { throw
error; }
struct throw_error_handler : error_handler {
template<class Error>
[[noreturn]] static auto error(const Error& error) -> void {
throw error;
}
};
} // namespace boost::openmethod::policies

View File

@@ -1,13 +1,13 @@
:example: ../examples/rolex
## Friendship
[#friendship]
Note;; This section uses overrider containers, described in the
xref:headers.adoc[Headers] section.
`friend` is a controversial feature. OpenMethod aims to interact well with
all of C++, as much as feasible for a library, and leave the user the choice of
using `friend`, or not.
`friend` is a controversial feature. OpenMethod aims to interact well with all
of C++, as much as feasible for a library, and leaves the choice of using
`friend`, or not, to the user.
Let's consider yet another variation of the `pay` example. This time, we want to
update a `balance` variable in a `Payroll` class, when an employee is paid. Thus

View File

@@ -1,6 +1,6 @@
:example: ../examples/rolex
## Headers
[#Headers]
Typically, `BOOST_OPENMETHOD` is used in headers, while
`BOOST_OPENMETHOD_CLASSES` and `BOOST_OPENMETHOD_OVERRIDE` are used in
@@ -8,8 +8,8 @@ implementation files.
Let's use a payroll application as an example. We have two roles: `Employee` and
`Salesman`, and a `pay` method that computes the monthly pay of an employee. We
want to override and call `pay` from from multiple translation units, so we put
it in a header:
want to override and call `pay` from multiple translation units, so we put it in
a header:
[source,c++]
----

View File

@@ -1,5 +1,6 @@
:example: ../examples
[#boost-openmethod]
= Boost.OpenMethod
Boost.OpenMethod implements open-(multi-)methods in C++17 and above.
@@ -72,18 +73,18 @@ manager.
Thanks to the members of the Boost community who posted a formal review:
* Joaquin M López Muñoz
* Andrzej Krzemienski
* Christian Mazakas
* Joaquin M López Muñoz
* Klemens Morgenstern
* Ruben Perez
* Yannick Le Goc
* Klemens Morgenstern
* Andrzej Krzemienski
Also thanks to Steven Watanabe for his cogent feedback and advice, and all
the people who posted remarks and suggestions.

View File

@@ -1,5 +1,5 @@
## Introduction
[#motivation]
Consider a class hierarchy that represents and evaluates arithmetic
expressions:
@@ -84,9 +84,12 @@ Julia, Cecil, TADS, and others, have multi-methods.
But wait! What do multi-methods have to do with our problem? There is no
multiple dispatch going on here! The thing is, "multi-methods" is not a very
good name. Even in languages that support them, multi-methods tend to use single
dispatch only. For that reason, we prefer the term "open-methods", to emphasize
the important feature: openness. Multiple dispatch is just a bonus.
good name. Even in languages that support them, many "multi-methods" have a
single virtual parameter - they are uni-methods
footnote:[https://figshare.com/articles/thesis/Multiple_Dispatch_in_Practice/16959112[Multiple
dispatch in practice], Radu Muschevici, 2008.]! For that reason, we prefer the
term "open-methods", to emphasize the important feature: openness. Multiple
dispatch is just a bonus.
An open-method is like a virtual function, but it exists outside of a class, as
a free-standing function. We can create all the open-methods we need, without

View File

@@ -1,12 +1,12 @@
:example: ../examples
## Multiple Dispatch
[#multiple_dispatch]
A method can have more than one virtual parameter. This is often called
"multi-methods" or "multiple dispatch". All the virtual parameters participate
"multi-method" or "multiple dispatch". All the virtual parameters participate
equally in overrider selection, following the same rules as those governing
overload resolution - except that the selection happens at runtime, and takes
into account the argument's dynamic types.
into account the arguments dynamic types.
Multiple dispatch is occasionally useful. When it is needed, it can be difficult
to implement correctly and efficiently by hand. For example, given the following

View File

@@ -1,9 +1,9 @@
:example: ../examples/rolex
## Namespaces
[#namespaces]
Note;; This section uses overrider containers, described in the
xref:headers.adoc[Headers] section.
xref:headers.adoc[Headers and Implementation Files] section.
xref:BOOST_OPENMETHOD.adoc[BOOST_OPENMETHOD] defines a method in the current
namespace. xref:BOOST_OPENMETHOD_OVERRIDE.adoc[BOOST_OPENMETHOD_OVERRIDE] works
@@ -13,9 +13,9 @@ called with the same arguments as the overrider, possibly located via argument
dependant lookup.
Overrider containers are added to the current namespace. It follows that the
same method can have overriders in several different container, in different
namespaces. This must be taken into account when calling an overrider
explicitly. Let's put Employee and Salesman in their own namespaces:
same method can have overriders in multiple containers, in different namespaces.
This must be taken into account when calling an overrider explicitly. Let's put
Employee and Salesman in their own namespaces:
[source,c++]
----

View File

@@ -1,5 +1,5 @@
## Performance
[#performance]
Open-methods can be as fast as ordinary virtual member functions when
compiled with optimization.
@@ -67,7 +67,7 @@ than calling the equivalent virtual function, with an empty body and no other
arguments. In most real programs, the overhead would be unnoticeable.
*However*, `call_via_ref` does two things: it constructs a `virtual_ptr<Node>`
from a `const Node&`; and then it calls the method.
from a `const Node&`, then it calls the method.
The construction of the `virtual_ptr` is the costly part. It performs a lookup
in a perfect hash table, indexed by pointers to `std::type_info`, to find the
@@ -96,9 +96,10 @@ jmp rax # TAILCALL
`virtual_ptr` arguments are passed through the method call, to the overrider,
which can use them to make further method calls.
A program designed with open-methods in mind should use `virtual_ptr`{empty}s
in place of plain pointers or references, as much as possible. Here is the Node
example, rewritten to use `virtual_ptr`{empty}s thoughout:
Code that incorporates open-methods in its design should use
`virtual_ptr`{empty}s in place of plain pointers or references, as much as
possible. Here is the Node example, rewritten to use `virtual_ptr`{empty}s
thoughout:
[source,c++]
----

View File

@@ -7,21 +7,64 @@
The following headers are sufficient for most basic uses of the library.
* xref:#main[`boost/openmethod.hpp`] to define open-methods and overriders using
* xref:#openmethod[`<boost/openmethod.hpp>`] to define open-methods and overriders using
convenient macros.
* xref:#initialize[`boost/openmethod/initialize.hpp`] to initialize the library.
* xref:#initialize[`<boost/openmethod/initialize.hpp>`] to initialize the library.
Typically only included in the translation unit containing `main`.
The following headers make it possible to use standard smart pointers in virtual
parameters:
* xref:#std_shared_ptr[`boost/openmethod/interop/std_shared_ptr.hpp`] to use
* xref:#std_shared_ptr[`<boost/openmethod/interop/std_shared_ptr.hpp>`] to use
`std::shared_ptr` in virtual parameters.
* xref:#std_unique_ptr[`boost/openmethod/interop/std_unique_ptr.hpp`] to use
* xref:#std_unique_ptr[`<boost/openmethod/interop/std_unique_ptr.hpp>`] to use
`std::unique_ptr` in virtual parameters.
## High-level Headers
[#core]
### link:{{BASE_URL}}/include/boost/openmethod/core.hpp[<boost/openmethod/core.hpp>]
Defines the main constructs of the library: methods, overriders and virtual
pointers, and mechanisms to implement them. Does not define any public macros
apart from `BOOST_OPENMETHOD_DEFAULT_REGISTRY`, if it is not defined already.
[#macros]
### link:{{BASE_URL}}/include/boost/openmethod/macros.hpp[<boost/openmethod/macros.hpp>]
Defines the public macros of the library, such as `BOOST_OPENMETHOD`,
`BOOST_OPENMETHOD_CLASSES`, etc.
There is little point in including this header directly, as this has the same
effect as including `boost/openmethod.hpp`, which is shorter.
[#openmethod]
### link:{{BASE_URL}}/include/boost/openmethod.hpp[<boost/openmethod.hpp>]
Includes `core.hpp` and `macros.hpp`.
[#initialize]
### link:{{BASE_URL}}/include/boost/openmethod/initialize.hpp[<boost/initialize.hpp>]
Provides the cpp:initialize[] and cpp:finalize[] functions. This header is
typically included in the translation unit containing `main`. Translation units
that dynamically load or unload shared libraries may also need to call those
functions.
[#std_shared_ptr]
### link:{{BASE_URL}}/include/boost/openmethod/interop/std_shared_ptr.hpp[<boost/openmethod/interop/std_shared_ptr.hpp>]
Provides a `virtual_traits` specialization that makes it possible to use a
`std::shared_ptr` in place of a raw pointer or reference in virtual parameters.
[#std_unique_ptr]
### link:{{BASE_URL}}/include/boost/openmethod/interop/std_unique_ptr.hpp[<boost/openmethod/interop/std_unique_ptr.hpp>]
Provides a `virtual_traits` specialization that makes it possible to use a
`std::unique_ptr` in place of a raw pointer or reference in virtual parameters.
*The headers below are for advanced use*.
## Pre-Core Headers
@@ -30,82 +73,52 @@ The following headers can be included before `core.hpp` to define custom
registries and policies, and override the default registry by defining
xref:BOOST_OPENMETHOD_DEFAULT_REGISTRY.adoc[`BOOST_OPENMETHOD_DEFAULT_REGISTRY`].
### boost/openmethod/preamble.hpp
### link:{{BASE_URL}}/include/boost/openmethod/preamble.hpp[<boost/openmethod/preamble.hpp>]
Defines `registry` and stock policy categories. Also defines all types and
functions necessary for the definition of `registry`.
### boost/openmethod/policies/std_rtti.hpp
### link:{{BASE_URL}}/include/boost/openmethod/policies/std_rtti.hpp[<boost/openmethod/policies/std_rtti.hpp>]
Provides an implementation of the `rtti` policy using standard RTTI.
### boost/openmethod/policies/fast_perfect_hash.hpp
### link:{{BASE_URL}}/include/boost/openmethod/policies/fast_perfect_hash.hpp[<boost/openmethod/policies/fast_perfect_hash.hpp>]
Provides an implementation of the `hash` policy using a fast perfect hash
function.
### boost/openmethod/policies/vptr_vector.hpp
### link:{{BASE_URL}}/include/boost/openmethod/policies/vptr_vector.hpp[<boost/openmethod/policies/vptr_vector.hpp>]
Provides an implementation of the `vptr` policy that stores the v-table pointers
in a `std::vector` indexed by type ids, possibly hashed.
### boost/openmethod/policies/default_error_handler.hpp
### link:{{BASE_URL}}/include/boost/openmethod/policies/default_error_handler.hpp[<boost/openmethod/policies/default_error_handler.hpp>]
Provides an implementation of the `error_handler` policy that calls a
`std::function<void(openmethod_error)>` when an error is encountered, and before
the library aborts the program.
### boost/openmethod/policies/stderr_output.hpp
### link:{{BASE_URL}}/include/boost/openmethod/policies/stderr_output.hpp[<boost/openmethod/policies/stderr_output.hpp>]
Provides an implementation of the `output` policy that writes diagnostics to
the C standard error stream (not using iostreams).
### boost/openmethod/default_registry.hpp
### link:{{BASE_URL}}/include/boost/openmethod/default_registry.hpp[<boost/openmethod/default_registry.hpp>]
Defines the default registry, which contains all the stock policies listed
above. Includes all the headers listed in the preamble section so far.
above. Includes all the headers listed in this section so far.
### boost/openmethod/policies/static_rtti.hpp
### link:{{BASE_URL}}/include/boost/openmethod/policies/static_rtti.hpp[<boost/openmethod/policies/static_rtti.hpp>]
Provides a minimal implementation of the `rtti` policy that does not depend on
standard RTTI.
### boost/openmethod/policies/throw_error_handler.hpp
### link:{{BASE_URL}}/include/boost/openmethod/policies/throw_error_handler.hpp[<boost/openmethod/policies/throw_error_handler.hpp>]
Provides an implementation of the `error_handler` policy that throws errors as
exceptions.
### boost/openmethod/policies/vptr_map.hpp
### link:{{BASE_URL}}/include/boost/openmethod/policies/vptr_map.hpp[<boost/openmethod/policies/vptr_map.hpp>]
Provides an implementation of the `vptr` policy that stores the v-table pointers
in a map (by default a `std::map`) indexed by type ids.
## High-level Headers
### boost/openmethod/core.hpp
Defines the main constructs of the library: methods, overriders and virtual
pointers, and mechanisms to implement them. Does not define any public macros
apart from `BOOST_OPENMETHOD_DEFAULT_REGISTRY`, if it is not defined already.
### boost/openmethod/macros.hpp
Defines the public macros of the library, such as `BOOST_OPENMETHOD`,
`BOOST_OPENMETHOD_CLASSES`, etc.
There is little point in including this header directly, as this has the same
effect as including `boost/openmethod.hpp`, which is shorter.
### boost/openmethod.hpp
Includes `core.hpp` and `macros.hpp`.
### boost/openmethod/interop/std_shared_ptr.hpp
Provides a `virtual_traits` specialization that make it possible to use a
`std::shared_ptr` in place of a raw pointer or reference in virtual parameters.
### boost/openmethod/interop/std_unique_ptr.hpp
Provides a `virtual_traits` specialization that make it possible to use a
`std::unique_ptr` in place of a raw pointer or reference in virtual parameters.

View File

@@ -1,6 +1,5 @@
[#macros]
= xref:macros.adoc[Macros]
:mrdocs:
[#ref_macros]
= xref:ref_macros.adoc[Macros]
The following macros - in particular the first three- are sufficient for most
uses of the library.

View File

@@ -1,5 +1,5 @@
## Registries and Policies
[#registries_and_policies]
Methods are scoped in a registry. A method can only reference classes in the
same registry. If a class is used as a virtual parameter in methods using
@@ -20,9 +20,9 @@ A registry has a collection of _policies_. Each policy belongs to a policy
category. A registry may contain at most one policy of each category. Policies
control how type information is obtained, how vptrs are acquired, how errors are
handled and reported, etc. While the behavior of cpp:initialize[] can be
customized via options, policies are primarily involved in in method dispatch.
customized via options, policies are primarily involved in method dispatch.
Policies are placed in the `boost::openmethod::policies` namespace.
Policies are placed in the cpp:boost::openmethod::policies[] namespace.
`default_registry` contains the following policies:
@@ -40,11 +40,11 @@ Policies are placed in the `boost::openmethod::policies` namespace.
| type_hash
| fast_perfect_hash
| hash type id to an index in a vector
| hashes type id to an index in a vector
| error_handler
| default_error_handler
| handles errors
| calls an overridable handler function
| output
| stderr_output
@@ -61,7 +61,7 @@ registrations that could not be caught by `initialize`.
The library provides another predefined registry: cpp:indirect_registry[]. It is
useful when shared libraries are dynamically loaded at runtime, and add methods
and overriders across program and shared library boundaries. See the section
about shared_libraries.adoc[shared libraries].
about xref:shared_libraries.adoc[shared libraries].
Registries can be created from scratch, using the `registry` template. Here is
the definition of `default_registry`, copied from
@@ -99,9 +99,9 @@ struct indirect_registry : default_registry::with<policies::indirect_vptr> {};
Policies are implemented as unary
https://www.boost.org/doc/libs/1_89_0/libs/mp11/doc/html/mp11.html[Boost.MP11
quoted metafunctions]. A policy is an ordinary class that contains a nested
class template, called `fn` which is instantiated by the registry, passing
itself as the template argument. The reason for this mechanism is to allow
policies that have static data members to give each registry its own copy.
class template `fn`, which is instantiated by the registry, passing itself as
the single template argument. The reason for this mechanism is to allow policies
to have static data members, which each registry must have its own set of.
`vptr_vector`, for example, stores v-table pointers in a `std::vector`. If it is
used in two different registries, it needs to use two different vectors, one for
each registry.

View File

@@ -1,6 +1,6 @@
:shared: ../examples/shared_libs
## Shared Libraries
[#shared_libraries]
This section discusses how OpenMethod interoperates with shared libraries on
Linux, other POSIX-like platforms, and Windows.
@@ -79,7 +79,7 @@ include::{shared}/dynamic_main.cpp[tag=unload]
### Windows
If we try the aboveexample on Windows, the result is disappointing:
If we try the example on Windows, the result is disappointing:
```
Before loading the shared library.
@@ -98,7 +98,7 @@ they add overriders to _their_ copy of the method (the `method::fn` static
variable for the given name and signature). They are ignored when the main
program calls `initialize`.
Likewise, `BOOST_OPENMETHOD_CLASSES(Tiger, Carnivore);` in the DLL adds `Tiger`
Likewise, `BOOST_OPENMETHOD_CLASSES(Tiger, Carnivore)` in the DLL adds `Tiger`
to the DLL's copy of the registry. For the perspective of the program's
registry, the class does not exist.

View File

@@ -1,5 +1,5 @@
## Smart Pointers
[#smart_pointers]
If we want maximum performance, we want to use `virtual_ptr`{empty}s in place of
ordinary pointers or references. However, we may also want to use smart pointers
@@ -20,10 +20,10 @@ v-table pointer.
Smart `virtual_ptr`{empty}s automatically convert to their non-smart, "plain"
counterparts - e.g. from `virtual_ptr<std::unique_ptr<const Node>>` to
`virtual_ptr<const Node>`. Methods and overriders typically use plain
`virtual_ptr`{empty}s, although it is not always the case. For example,
`virtual_ptr`{empty}s, although it is not always the case footnote:[For example,
consider a `transpose` method for matrices. If the matrix is symmetric, the
overrider should return its argument. This can be implemented by passing a
`virtual_ptr<std::shared_ptr<const Matrix>>` to the method.
`virtual_ptr<std::shared_ptr<const Matrix>>` to the method.].
The reverse conversion, from plain to smart, does not exist, because it would
have the potential to accidentally create smart pointers. Likewise, a smart

View File

@@ -1,5 +1,6 @@
:example: ../examples/virtual_ptr_alt
[#virtual_ptr_alt]
## Alternatives to virtual_ptr
Virtual arguments can also be passed as plain references, plain pointers, or

View File

@@ -17,13 +17,13 @@ implementation-defined:
- 'boost::openmethod::detail'
inaccessible-members: never
inaccessible-bases: never
# see-below:
# - 'boost::urls::format_arg'
# implementation-defined:
# - 'boost::openmethod::detail::**'
exclude-symbols:
- 'boost::openmethod::registry::compiler'
- 'boost::openmethod::registry::initialize'
- 'boost::openmethod::registry::finalize'
- 'boost::openmethod::boost_openmethod_bases'
- 'boost::openmethod::boost_openmethod_registry'
- 'boost::openmethod::registry::compiler'
sort-members: false
# sort-namespace-members-by: location
@@ -36,7 +36,7 @@ auto-function-metadata: false
# Generator
generate: adoc
base-url: https://www.github.com/boostorg/openmethod/blob/develop/
base-url: https://www.github.com/boostorg/openmethod/blob/master/
# Style
verbose: true

599
doc/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +1,15 @@
{
"devDependencies": {
"@antora/cli": "3.1.10",
"@antora/site-generator": "3.1.10",
"antora": "3.1.10"
"@antora/cli": "3.1.14",
"@antora/site-generator": "3.1.14",
"antora": "3.1.14"
},
"dependencies": {
"@antora/expand-path-helper": "^2.0.0",
"@antora/lunr-extension": "^1.0.0-alpha.8",
"@asciidoctor/tabs": "^1.0.0-beta.3",
"@cppalliance/antora-cpp-reference-extension": "^0.0.8",
"@cppalliance/antora-cpp-tagfiles-extension": "^0.0.5",
"@antora/expand-path-helper": "^3.0.0",
"@antora/lunr-extension": "^1.0.0-alpha.12",
"@asciidoctor/tabs": "^1.0.0-beta.6",
"@cppalliance/antora-cpp-reference-extension": "^0.1.0",
"@cppalliance/antora-cpp-tagfiles-extension": "^0.1.0",
"@cppalliance/asciidoctor-boost-links": "^0.0.2"
}
}

View File

@@ -1,907 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<tagfile>
<compound kind="namespace">
<name>boost::openmethod</name>
<filename>boost/openmethod.adoc</filename>
<class kind="class">boost::openmethod::shared_virtual_ptr</class>
<class kind="class">boost::openmethod::type_id</class>
<class kind="class">boost::openmethod::unique_virtual_ptr</class>
<class kind="class">boost::openmethod::vptr_type</class>
<class kind="class">boost::openmethod::LightweightOutputStream</class>
<class kind="class">boost::openmethod::StripVirtualDecorator</class>
<class kind="class">boost::openmethod::StripVirtualDecorator</class>
<class kind="class">boost::openmethod::VirtualTraits</class>
<class kind="class">boost::openmethod::ambiguous_call</class>
<class kind="class">boost::openmethod::bad_call</class>
<class kind="class">boost::openmethod::default_registry</class>
<class kind="class">boost::openmethod::final_error</class>
<class kind="class">boost::openmethod::indirect_registry</class>
<class kind="class">boost::openmethod::inplace_vptr_base</class>
<class kind="class">boost::openmethod::inplace_vptr_derived</class>
<class kind="class">boost::openmethod::inplace_vptr_derived</class>
<class kind="class">boost::openmethod::inplace_vptr_derived</class>
<class kind="class">boost::openmethod::method</class>
<class kind="class">boost::openmethod::method</class>
<class kind="class">boost::openmethod::missing_base</class>
<class kind="class">boost::openmethod::missing_class</class>
<class kind="class">boost::openmethod::n2216</class>
<class kind="class">boost::openmethod::no_overrider</class>
<class kind="class">boost::openmethod::not_initialized</class>
<class kind="class">boost::openmethod::odr_violation</class>
<class kind="class">boost::openmethod::openmethod_error</class>
<class kind="class">boost::openmethod::registry</class>
<class kind="class">boost::openmethod::trace</class>
<class kind="class">boost::openmethod::use_classes</class>
<class kind="class">boost::openmethod::virtual_</class>
<class kind="class">boost::openmethod::virtual_ptr</class>
<class kind="class">boost::openmethod::virtual_ptr</class>
<class kind="class">boost::openmethod::virtual_traits</class>
<class kind="class">boost::openmethod::virtual_traits</class>
<class kind="class">boost::openmethod::virtual_traits</class>
<class kind="class">boost::openmethod::virtual_traits</class>
<class kind="class">boost::openmethod::virtual_traits</class>
<class kind="class">boost::openmethod::virtual_traits</class>
<class kind="class">boost::openmethod::virtual_traits</class>
<class kind="class">boost::openmethod::virtual_traits</class>
<class kind="class">boost::openmethod::virtual_traits</class>
<class kind="class">boost::openmethod::final_virtual_ptr</class>
<class kind="class">boost::openmethod::IsPolymorphic</class>
<class kind="class">boost::openmethod::IsSmartPtr</class>
<class kind="class">boost::openmethod::SameSmartPtr</class>
<class kind="class">boost::openmethod::virtual_ptr</class>
<class kind="class">boost::openmethod::virtual_ptr</class>
<member kind="function">
<type>void</type>
<name>finalize</name>
<anchorfile>boost/openmethod/finalize.adoc</anchorfile>
<anchor/>
<arglist>()</arglist>
</member>
<member kind="function">
<type>auto</type>
<name>initialize</name>
<anchorfile>boost/openmethod/initialize.adoc</anchorfile>
<anchor/>
<arglist>(...Options...&amp;&amp; options)</arglist>
</member>
<member kind="function">
<type>auto</type>
<name>make_shared_virtual</name>
<anchorfile>boost/openmethod/make_shared_virtual.adoc</anchorfile>
<anchor/>
<arglist>(...T...&amp;&amp; args)</arglist>
</member>
<member kind="function">
<type>auto</type>
<name>make_unique_virtual</name>
<anchorfile>boost/openmethod/make_unique_virtual.adoc</anchorfile>
<anchor/>
<arglist>(...T...&amp;&amp; args)</arglist>
</member>
<member kind="function">
<type>bool</type>
<name>operator==</name>
<anchorfile>boost/openmethod/operator_eq.adoc</anchorfile>
<anchor/>
<arglist>(const virtual_ptr&lt;Left, Registry&gt;&amp; left, const virtual_ptr&lt;Right, Registry&gt;&amp; right)</arglist>
</member>
<member kind="function">
<type>bool</type>
<name>operator!=</name>
<anchorfile>boost/openmethod/operator_not_eq.adoc</anchorfile>
<anchor/>
<arglist>(const virtual_ptr&lt;Left, Registry&gt;&amp; left, const virtual_ptr&lt;Right, Registry&gt;&amp; right)</arglist>
</member>
</compound>
<compound kind="namespace">
<name>boost::openmethod::aliases</name>
<filename>boost/openmethod/aliases.adoc</filename>
<class kind="class">boost::openmethod::aliases::final_virtual_ptr</class>
<class kind="class">boost::openmethod::aliases::initialize</class>
<class kind="class">boost::openmethod::aliases::inplace_vptr_base</class>
<class kind="class">boost::openmethod::aliases::inplace_vptr_derived</class>
<class kind="class">boost::openmethod::aliases::make_shared_virtual</class>
<class kind="class">boost::openmethod::aliases::make_unique_virtual</class>
<class kind="class">boost::openmethod::aliases::shared_virtual_ptr</class>
<class kind="class">boost::openmethod::aliases::unique_virtual_ptr</class>
<class kind="class">boost::openmethod::aliases::virtual_</class>
<class kind="class">boost::openmethod::aliases::virtual_ptr</class>
</compound>
<compound kind="class">
<name>boost::openmethod::aliases::final_virtual_ptr</name>
<filename>boost/openmethod/aliases/final_virtual_ptr.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::aliases::initialize</name>
<filename>boost/openmethod/aliases/initialize.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::aliases::inplace_vptr_base</name>
<filename>boost/openmethod/aliases/inplace_vptr_base.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::aliases::inplace_vptr_derived</name>
<filename>boost/openmethod/aliases/inplace_vptr_derived.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::aliases::make_shared_virtual</name>
<filename>boost/openmethod/aliases/make_shared_virtual.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::aliases::make_unique_virtual</name>
<filename>boost/openmethod/aliases/make_unique_virtual.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::aliases::shared_virtual_ptr</name>
<filename>boost/openmethod/aliases/shared_virtual_ptr.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::aliases::unique_virtual_ptr</name>
<filename>boost/openmethod/aliases/unique_virtual_ptr.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::aliases::virtual_</name>
<filename>boost/openmethod/aliases/virtual_.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::aliases::virtual_ptr</name>
<filename>boost/openmethod/aliases/virtual_ptr.adoc</filename>
</compound>
<compound kind="namespace">
<name>boost::openmethod::policies</name>
<filename>boost/openmethod/policies.adoc</filename>
<class kind="class">boost::openmethod::policies::ErrorHandlerFn</class>
<class kind="class">boost::openmethod::policies::IdsToVptr</class>
<class kind="class">boost::openmethod::policies::OutputFn</class>
<class kind="class">boost::openmethod::policies::RttiFn</class>
<class kind="class">boost::openmethod::policies::TypeHashFn</class>
<class kind="class">boost::openmethod::policies::VptrFn</class>
<class kind="class">boost::openmethod::policies::default_error_handler</class>
<class kind="class">boost::openmethod::policies::deferred_static_rtti</class>
<class kind="class">boost::openmethod::policies::error_handler</class>
<class kind="class">boost::openmethod::policies::fast_perfect_hash</class>
<class kind="class">boost::openmethod::policies::indirect_vptr</class>
<class kind="class">boost::openmethod::policies::output</class>
<class kind="class">boost::openmethod::policies::rtti</class>
<class kind="class">boost::openmethod::policies::runtime_checks</class>
<class kind="class">boost::openmethod::policies::static_rtti</class>
<class kind="class">boost::openmethod::policies::std_rtti</class>
<class kind="class">boost::openmethod::policies::stderr_output</class>
<class kind="class">boost::openmethod::policies::throw_error_handler</class>
<class kind="class">boost::openmethod::policies::type_hash</class>
<class kind="class">boost::openmethod::policies::vptr</class>
<class kind="class">boost::openmethod::policies::vptr_map</class>
<class kind="class">boost::openmethod::policies::vptr_vector</class>
</compound>
<compound kind="class">
<name>boost::openmethod::policies::ErrorHandlerFn</name>
<filename>boost/openmethod/policies/ErrorHandlerFn.adoc</filename>
<member kind="function">
<type>void</type>
<name>error</name>
<anchorfile>boost/openmethod/policies/ErrorHandlerFn/error.adoc</anchorfile>
<anchor/>
<arglist>(const auto&amp; error)</arglist>
</member>
</compound>
<compound kind="class">
<name>boost::openmethod::policies::IdsToVptr</name>
<filename>boost/openmethod/policies/IdsToVptr.adoc</filename>
<member kind="function">
<type>auto</type>
<name>type_id_begin</name>
<anchorfile>boost/openmethod/policies/IdsToVptr/type_id_begin.adoc</anchorfile>
<anchor/>
<arglist>()</arglist>
</member>
<member kind="function">
<type>auto</type>
<name>type_id_end</name>
<anchorfile>boost/openmethod/policies/IdsToVptr/type_id_end.adoc</anchorfile>
<anchor/>
<arglist>()</arglist>
</member>
<member kind="function">
<type>const vptr_type&amp;</type>
<name>vptr</name>
<anchorfile>boost/openmethod/policies/IdsToVptr/vptr.adoc</anchorfile>
<anchor/>
<arglist>()</arglist>
</member>
</compound>
<compound kind="class">
<name>boost::openmethod::policies::OutputFn</name>
<filename>boost/openmethod/policies/OutputFn.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::policies::RttiFn</name>
<filename>boost/openmethod/policies/RttiFn.adoc</filename>
<member kind="function">
<type>type_id</type>
<name>static_type</name>
<anchorfile>boost/openmethod/policies/RttiFn/static_type.adoc</anchorfile>
<anchor/>
<arglist>()</arglist>
</member>
<member kind="function">
<type>type_id</type>
<name>dynamic_type</name>
<anchorfile>boost/openmethod/policies/RttiFn/dynamic_type.adoc</anchorfile>
<anchor/>
<arglist>(const Class&amp; obj)</arglist>
</member>
<member kind="function">
<type>auto</type>
<name>type_name</name>
<anchorfile>boost/openmethod/policies/RttiFn/type_name.adoc</anchorfile>
<anchor/>
<arglist>(type_id type, Stream&amp; stream)</arglist>
</member>
<member kind="function">
<type>auto</type>
<name>type_index</name>
<anchorfile>boost/openmethod/policies/RttiFn/type_index.adoc</anchorfile>
<anchor/>
<arglist>(type_id type)</arglist>
</member>
<member kind="function">
<type>D</type>
<name>dynamic_cast_ref</name>
<anchorfile>boost/openmethod/policies/RttiFn/dynamic_cast_ref.adoc</anchorfile>
<anchor/>
<arglist>(B&amp;&amp; obj)</arglist>
</member>
</compound>
<compound kind="class">
<name>boost::openmethod::policies::TypeHashFn</name>
<filename>boost/openmethod/policies/TypeHashFn.adoc</filename>
<member kind="function">
<type>std::pair&lt;std::size_t, std::size_t&gt;</type>
<name>initialize</name>
<anchorfile>boost/openmethod/policies/TypeHashFn/initialize.adoc</anchorfile>
<anchor/>
<arglist>(ForwardIterator first, ForwardIterator last)</arglist>
</member>
<member kind="function">
<type>std::size_t</type>
<name>hash</name>
<anchorfile>boost/openmethod/policies/TypeHashFn/hash.adoc</anchorfile>
<anchor/>
<arglist>(type_id type)</arglist>
</member>
<member kind="function">
<type>void</type>
<name>finalize</name>
<anchorfile>boost/openmethod/policies/TypeHashFn/finalize.adoc</anchorfile>
<anchor/>
<arglist>()</arglist>
</member>
</compound>
<compound kind="class">
<name>boost::openmethod::policies::VptrFn</name>
<filename>boost/openmethod/policies/VptrFn.adoc</filename>
<member kind="function">
<type>auto</type>
<name>initialize</name>
<anchorfile>boost/openmethod/policies/VptrFn/initialize.adoc</anchorfile>
<anchor/>
<arglist>(ForwardIterator first, ForwardIterator last, std::tuple&lt;Options...&gt; opts)</arglist>
</member>
<member kind="function">
<type>const vptr_type&amp;</type>
<name>dynamic_vptr</name>
<anchorfile>boost/openmethod/policies/VptrFn/dynamic_vptr.adoc</anchorfile>
<anchor/>
<arglist>(const Class&amp; arg)</arglist>
</member>
<member kind="function">
<type>void</type>
<name>finalize</name>
<anchorfile>boost/openmethod/policies/VptrFn/finalize.adoc</anchorfile>
<anchor/>
<arglist>(std::tuple&lt;Options...&gt; opts)</arglist>
</member>
</compound>
<compound kind="class">
<name>boost::openmethod::policies::default_error_handler</name>
<filename>boost/openmethod/policies/default_error_handler.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::policies::deferred_static_rtti</name>
<filename>boost/openmethod/policies/deferred_static_rtti.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::policies::error_handler</name>
<filename>boost/openmethod/policies/error_handler.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::policies::fast_perfect_hash</name>
<filename>boost/openmethod/policies/fast_perfect_hash.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::policies::indirect_vptr</name>
<filename>boost/openmethod/policies/indirect_vptr.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::policies::output</name>
<filename>boost/openmethod/policies/output.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::policies::rtti</name>
<filename>boost/openmethod/policies/rtti.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::policies::runtime_checks</name>
<filename>boost/openmethod/policies/runtime_checks.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::policies::static_rtti</name>
<filename>boost/openmethod/policies/static_rtti.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::policies::std_rtti</name>
<filename>boost/openmethod/policies/std_rtti.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::policies::stderr_output</name>
<filename>boost/openmethod/policies/stderr_output.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::policies::throw_error_handler</name>
<filename>boost/openmethod/policies/throw_error_handler.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::policies::type_hash</name>
<filename>boost/openmethod/policies/type_hash.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::policies::vptr</name>
<filename>boost/openmethod/policies/vptr.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::policies::vptr_map</name>
<filename>boost/openmethod/policies/vptr_map.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::policies::vptr_vector</name>
<filename>boost/openmethod/policies/vptr_vector.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::shared_virtual_ptr</name>
<filename>boost/openmethod/shared_virtual_ptr.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::type_id</name>
<filename>boost/openmethod/type_id.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::unique_virtual_ptr</name>
<filename>boost/openmethod/unique_virtual_ptr.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::vptr_type</name>
<filename>boost/openmethod/vptr_type.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::LightweightOutputStream</name>
<filename>boost/openmethod/LightweightOutputStream.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::StripVirtualDecorator</name>
<filename>boost/openmethod/StripVirtualDecorator-020.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::StripVirtualDecorator</name>
<filename>boost/openmethod/StripVirtualDecorator-028.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::VirtualTraits</name>
<filename>boost/openmethod/VirtualTraits.adoc</filename>
<member kind="function">
<type>const virtual_type&amp;</type>
<name>peek</name>
<anchorfile>boost/openmethod/VirtualTraits/peek.adoc</anchorfile>
<anchor/>
<arglist>(T arg)</arglist>
</member>
<member kind="function">
<type>U</type>
<name>cast</name>
<anchorfile>boost/openmethod/VirtualTraits/cast.adoc</anchorfile>
<anchor/>
<arglist>(T arg)</arglist>
</member>
</compound>
<compound kind="class">
<name>boost::openmethod::ambiguous_call</name>
<filename>boost/openmethod/ambiguous_call.adoc</filename>
<member kind="function">
<type>auto</type>
<name>write</name>
<anchorfile>boost/openmethod/ambiguous_call/write.adoc</anchorfile>
<anchor/>
<arglist>(Stream&amp; os)</arglist>
</member>
</compound>
<compound kind="class">
<name>boost::openmethod::bad_call</name>
<filename>boost/openmethod/bad_call.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::default_registry</name>
<filename>boost/openmethod/default_registry.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::final_error</name>
<filename>boost/openmethod/final_error.adoc</filename>
<member kind="function">
<type>auto</type>
<name>write</name>
<anchorfile>boost/openmethod/final_error/write.adoc</anchorfile>
<anchor/>
<arglist>(Stream&amp; os)</arglist>
</member>
</compound>
<compound kind="class">
<name>boost::openmethod::indirect_registry</name>
<filename>boost/openmethod/indirect_registry.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::inplace_vptr_base</name>
<filename>boost/openmethod/inplace_vptr_base.adoc</filename>
<member kind="function">
<type>void</type>
<name>inplace_vptr_base</name>
<anchorfile>boost/openmethod/inplace_vptr_base/2constructor.adoc</anchorfile>
<anchor/>
<arglist>()</arglist>
</member>
<member kind="function">
<type>void</type>
<name>~inplace_vptr_base</name>
<anchorfile>boost/openmethod/inplace_vptr_base/2destructor.adoc</anchorfile>
<anchor/>
<arglist>()</arglist>
</member>
</compound>
<compound kind="class">
<name>boost::openmethod::inplace_vptr_derived</name>
<filename>boost/openmethod/inplace_vptr_derived-00.adoc</filename>
<member kind="function">
<type>void</type>
<name>inplace_vptr_derived</name>
<anchorfile>boost/openmethod/inplace_vptr_derived-00/2constructor.adoc</anchorfile>
<anchor/>
<arglist>()</arglist>
</member>
<member kind="function">
<type>void</type>
<name>~inplace_vptr_derived</name>
<anchorfile>boost/openmethod/inplace_vptr_derived-00/2destructor.adoc</anchorfile>
<anchor/>
<arglist>()</arglist>
</member>
</compound>
<compound kind="class">
<name>boost::openmethod::inplace_vptr_derived</name>
<filename>boost/openmethod/inplace_vptr_derived-058.adoc</filename>
<member kind="function">
<type>void</type>
<name>inplace_vptr_derived</name>
<anchorfile>boost/openmethod/inplace_vptr_derived-058/2constructor.adoc</anchorfile>
<anchor/>
<arglist>()</arglist>
</member>
<member kind="function">
<type>void</type>
<name>~inplace_vptr_derived</name>
<anchorfile>boost/openmethod/inplace_vptr_derived-058/2destructor.adoc</anchorfile>
<anchor/>
<arglist>()</arglist>
</member>
</compound>
<compound kind="class">
<name>boost::openmethod::inplace_vptr_derived</name>
<filename>boost/openmethod/inplace_vptr_derived-056.adoc</filename>
<member kind="function">
<type>void</type>
<name>inplace_vptr_derived</name>
<anchorfile>boost/openmethod/inplace_vptr_derived-056/2constructor.adoc</anchorfile>
<anchor/>
<arglist>()</arglist>
</member>
<member kind="function">
<type>void</type>
<name>~inplace_vptr_derived</name>
<anchorfile>boost/openmethod/inplace_vptr_derived-056/2destructor.adoc</anchorfile>
<anchor/>
<arglist>()</arglist>
</member>
</compound>
<compound kind="class">
<name>boost::openmethod::method</name>
<filename>boost/openmethod/method-0d8.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::method</name>
<filename>boost/openmethod/method-0db.adoc</filename>
<member kind="function">
<type>ReturnType</type>
<name>operator()</name>
<anchorfile>boost/openmethod/method-0db/operator_call.adoc</anchorfile>
<anchor/>
<arglist>(...StripVirtualDecorator&lt;Parameters&gt;::type args)</arglist>
</member>
<member kind="function">
<type>bool</type>
<name>has_next</name>
<anchorfile>boost/openmethod/method-0db/has_next.adoc</anchorfile>
<anchor/>
<arglist>()</arglist>
</member>
</compound>
<compound kind="class">
<name>boost::openmethod::missing_base</name>
<filename>boost/openmethod/missing_base.adoc</filename>
<member kind="function">
<type>auto</type>
<name>write</name>
<anchorfile>boost/openmethod/missing_base/write.adoc</anchorfile>
<anchor/>
<arglist>(Stream&amp; os)</arglist>
</member>
</compound>
<compound kind="class">
<name>boost::openmethod::missing_class</name>
<filename>boost/openmethod/missing_class.adoc</filename>
<member kind="function">
<type>auto</type>
<name>write</name>
<anchorfile>boost/openmethod/missing_class/write.adoc</anchorfile>
<anchor/>
<arglist>(Stream&amp; os)</arglist>
</member>
</compound>
<compound kind="class">
<name>boost::openmethod::n2216</name>
<filename>boost/openmethod/n2216.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::no_overrider</name>
<filename>boost/openmethod/no_overrider.adoc</filename>
<member kind="function">
<type>auto</type>
<name>write</name>
<anchorfile>boost/openmethod/no_overrider/write.adoc</anchorfile>
<anchor/>
<arglist>(Stream&amp; os)</arglist>
</member>
</compound>
<compound kind="class">
<name>boost::openmethod::not_initialized</name>
<filename>boost/openmethod/not_initialized.adoc</filename>
<member kind="function">
<type>auto</type>
<name>write</name>
<anchorfile>boost/openmethod/not_initialized/write.adoc</anchorfile>
<anchor/>
<arglist>(Stream&amp; os)</arglist>
</member>
</compound>
<compound kind="class">
<name>boost::openmethod::odr_violation</name>
<filename>boost/openmethod/odr_violation.adoc</filename>
<member kind="function">
<type>auto</type>
<name>write</name>
<anchorfile>boost/openmethod/odr_violation/write.adoc</anchorfile>
<anchor/>
<arglist>(Stream&amp; stream)</arglist>
</member>
</compound>
<compound kind="class">
<name>boost::openmethod::openmethod_error</name>
<filename>boost/openmethod/openmethod_error.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::registry</name>
<filename>boost/openmethod/registry-07c.adoc</filename>
<member kind="function">
<type>void</type>
<name>require_initialized</name>
<anchorfile>boost/openmethod/registry-07c/require_initialized.adoc</anchorfile>
<anchor/>
<arglist>()</arglist>
</member>
<member kind="function">
<type>void</type>
<name>finalize</name>
<anchorfile>boost/openmethod/registry-07c/finalize.adoc</anchorfile>
<anchor/>
<arglist>(...Options opts)</arglist>
</member>
</compound>
<compound kind="class">
<name>boost::openmethod::trace</name>
<filename>boost/openmethod/trace.adoc</filename>
<member kind="function">
<type>void</type>
<name>trace</name>
<anchorfile>boost/openmethod/trace/2constructor.adoc</anchorfile>
<anchor/>
<arglist>(bool on)</arglist>
</member>
<member kind="function">
<type>trace</type>
<name>from_env</name>
<anchorfile>boost/openmethod/trace/from_env.adoc</anchorfile>
<anchor/>
<arglist>()</arglist>
</member>
</compound>
<compound kind="class">
<name>boost::openmethod::use_classes</name>
<filename>boost/openmethod/use_classes.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::virtual_</name>
<filename>boost/openmethod/virtual_.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::virtual_ptr</name>
<filename>boost/openmethod/virtual_ptr-0a.adoc</filename>
<member kind="function">
<type>Class*</type>
<name>get</name>
<anchorfile>boost/openmethod/virtual_ptr-0a/get.adoc</anchorfile>
<anchor/>
<arglist>()</arglist>
</member>
<member kind="function">
<type>auto</type>
<name>operator-&gt;</name>
<anchorfile>boost/openmethod/virtual_ptr-0a/operator_ptr.adoc</anchorfile>
<anchor/>
<arglist>()</arglist>
</member>
<member kind="function">
<type>element_type&amp;</type>
<name>operator*</name>
<anchorfile>boost/openmethod/virtual_ptr-0a/operator_star.adoc</anchorfile>
<anchor/>
<arglist>()</arglist>
</member>
<member kind="function">
<type>element_type*</type>
<name>pointer</name>
<anchorfile>boost/openmethod/virtual_ptr-0a/pointer.adoc</anchorfile>
<anchor/>
<arglist>()</arglist>
</member>
<member kind="function">
<type>decltype(auto)</type>
<name>cast</name>
<anchorfile>boost/openmethod/virtual_ptr-0a/cast.adoc</anchorfile>
<anchor/>
<arglist>()</arglist>
</member>
<member kind="function">
<type>auto</type>
<name>vptr</name>
<anchorfile>boost/openmethod/virtual_ptr-0a/vptr.adoc</anchorfile>
<anchor/>
<arglist>()</arglist>
</member>
<member kind="function">
<type>auto</type>
<name>final</name>
<anchorfile>boost/openmethod/virtual_ptr-0a/final.adoc</anchorfile>
<anchor/>
<arglist>(Other&amp;&amp; obj)</arglist>
</member>
</compound>
<compound kind="class">
<name>boost::openmethod::virtual_ptr</name>
<filename>boost/openmethod/virtual_ptr-0b5.adoc</filename>
<member kind="function">
<type>element_type*</type>
<name>get</name>
<anchorfile>boost/openmethod/virtual_ptr-0b5/get.adoc</anchorfile>
<anchor/>
<arglist>()</arglist>
</member>
<member kind="function">
<type>element_type*</type>
<name>operator-&gt;</name>
<anchorfile>boost/openmethod/virtual_ptr-0b5/operator_ptr.adoc</anchorfile>
<anchor/>
<arglist>()</arglist>
</member>
<member kind="function">
<type>element_type&amp;</type>
<name>operator*</name>
<anchorfile>boost/openmethod/virtual_ptr-0b5/operator_star.adoc</anchorfile>
<anchor/>
<arglist>()</arglist>
</member>
<member kind="function">
<type>const SmartPtr&amp;</type>
<name>pointer</name>
<anchorfile>boost/openmethod/virtual_ptr-0b5/pointer.adoc</anchorfile>
<anchor/>
<arglist>()</arglist>
</member>
<member kind="function">
<type>auto</type>
<name>vptr</name>
<anchorfile>boost/openmethod/virtual_ptr-0b5/vptr.adoc</anchorfile>
<anchor/>
<arglist>()</arglist>
</member>
<member kind="function">
<type>auto</type>
<name>final</name>
<anchorfile>boost/openmethod/virtual_ptr-0b5/final.adoc</anchorfile>
<anchor/>
<arglist>(Other&amp;&amp; obj)</arglist>
</member>
</compound>
<compound kind="class">
<name>boost::openmethod::virtual_traits</name>
<filename>boost/openmethod/virtual_traits-0be.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::virtual_traits</name>
<filename>boost/openmethod/virtual_traits-043.adoc</filename>
<member kind="function">
<type>const Class&amp;</type>
<name>peek</name>
<anchorfile>boost/openmethod/virtual_traits-043/peek.adoc</anchorfile>
<anchor/>
<arglist>(const std::shared_ptr&lt;Class&gt;&amp; arg)</arglist>
</member>
</compound>
<compound kind="class">
<name>boost::openmethod::virtual_traits</name>
<filename>boost/openmethod/virtual_traits-0bf.adoc</filename>
<member kind="function">
<type>const Class&amp;</type>
<name>peek</name>
<anchorfile>boost/openmethod/virtual_traits-0bf/peek.adoc</anchorfile>
<anchor/>
<arglist>(const std::unique_ptr&lt;Class&gt;&amp; arg)</arglist>
</member>
<member kind="function">
<type>auto</type>
<name>cast</name>
<anchorfile>boost/openmethod/virtual_traits-0bf/cast.adoc</anchorfile>
<anchor/>
<arglist>(std::unique_ptr&lt;Class&gt;&amp;&amp; ptr)</arglist>
</member>
</compound>
<compound kind="class">
<name>boost::openmethod::virtual_traits</name>
<filename>boost/openmethod/virtual_traits-096.adoc</filename>
<member kind="function">
<type>const virtual_ptr&lt;Class, Registry&gt;&amp;</type>
<name>peek</name>
<anchorfile>boost/openmethod/virtual_traits-096/peek.adoc</anchorfile>
<anchor/>
<arglist>(const virtual_ptr&lt;Class, Registry&gt;&amp; ptr)</arglist>
</member>
</compound>
<compound kind="class">
<name>boost::openmethod::virtual_traits</name>
<filename>boost/openmethod/virtual_traits-08.adoc</filename>
<member kind="function">
<type>const Class&amp;</type>
<name>peek</name>
<anchorfile>boost/openmethod/virtual_traits-08/peek.adoc</anchorfile>
<anchor/>
<arglist>(const Class&amp; arg)</arglist>
</member>
<member kind="function">
<type>Derived</type>
<name>cast</name>
<anchorfile>boost/openmethod/virtual_traits-08/cast.adoc</anchorfile>
<anchor/>
<arglist>(Class&amp; obj)</arglist>
</member>
</compound>
<compound kind="class">
<name>boost::openmethod::virtual_traits</name>
<filename>boost/openmethod/virtual_traits-07a.adoc</filename>
<member kind="function">
<type>const Class&amp;</type>
<name>peek</name>
<anchorfile>boost/openmethod/virtual_traits-07a/peek.adoc</anchorfile>
<anchor/>
<arglist>(const std::shared_ptr&lt;Class&gt;&amp; arg)</arglist>
</member>
<member kind="function">
<type>auto</type>
<name>cast</name>
<anchorfile>boost/openmethod/virtual_traits-07a/cast.adoc</anchorfile>
<anchor/>
<arglist>(const std::shared_ptr&lt;Class&gt;&amp; obj)</arglist>
</member>
</compound>
<compound kind="class">
<name>boost::openmethod::virtual_traits</name>
<filename>boost/openmethod/virtual_traits-048.adoc</filename>
<member kind="function">
<type>const virtual_ptr&lt;Class, Registry&gt;&amp;</type>
<name>peek</name>
<anchorfile>boost/openmethod/virtual_traits-048/peek.adoc</anchorfile>
<anchor/>
<arglist>(const virtual_ptr&lt;Class, Registry&gt;&amp; ptr)</arglist>
</member>
<member kind="function">
<type>decltype(auto)</type>
<name>cast</name>
<anchorfile>boost/openmethod/virtual_traits-048/cast.adoc</anchorfile>
<anchor/>
<arglist>(const virtual_ptr&lt;Class, Registry&gt;&amp; ptr)</arglist>
</member>
</compound>
<compound kind="class">
<name>boost::openmethod::virtual_traits</name>
<filename>boost/openmethod/virtual_traits-098.adoc</filename>
<member kind="function">
<type>const Class&amp;</type>
<name>peek</name>
<anchorfile>boost/openmethod/virtual_traits-098/peek.adoc</anchorfile>
<anchor/>
<arglist>(const Class&amp; arg)</arglist>
</member>
<member kind="function">
<type>Derived</type>
<name>cast</name>
<anchorfile>boost/openmethod/virtual_traits-098/cast.adoc</anchorfile>
<anchor/>
<arglist>(Class&amp;&amp; obj)</arglist>
</member>
</compound>
<compound kind="class">
<name>boost::openmethod::virtual_traits</name>
<filename>boost/openmethod/virtual_traits-071.adoc</filename>
<member kind="function">
<type>const Class&amp;</type>
<name>peek</name>
<anchorfile>boost/openmethod/virtual_traits-071/peek.adoc</anchorfile>
<anchor/>
<arglist>(const Class* arg)</arglist>
</member>
<member kind="function">
<type>Derived</type>
<name>cast</name>
<anchorfile>boost/openmethod/virtual_traits-071/cast.adoc</anchorfile>
<anchor/>
<arglist>(Class* ptr)</arglist>
</member>
</compound>
<compound kind="class">
<name>boost::openmethod::final_virtual_ptr</name>
<filename>boost/openmethod/final_virtual_ptr-04.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::IsPolymorphic</name>
<filename>boost/openmethod/IsPolymorphic.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::IsSmartPtr</name>
<filename>boost/openmethod/IsSmartPtr.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::SameSmartPtr</name>
<filename>boost/openmethod/SameSmartPtr.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::virtual_ptr</name>
<filename>boost/openmethod/virtual_ptr-0d.adoc</filename>
</compound>
<compound kind="class">
<name>boost::openmethod::virtual_ptr</name>
<filename>boost/openmethod/virtual_ptr-0b6.adoc</filename>
</compound>
</tagfile>

View File

@@ -192,7 +192,10 @@ using virtual_types = boost::mp11::mp_transform<
BOOST_OPENMETHOD_OPEN_NAMESPACE_DETAIL_UNLESS_MRDOCS
//! Remove virtual_<> decorator from a type (exposition only).
//! Removes the virtual_<> decorator, if present (exposition only).
//!
//! Provides a nested `type` equal to `T`. The template is specialized for
//! `virtual_<T>`.
//!
//! @tparam T A type.
template<typename T>
@@ -201,7 +204,11 @@ struct StripVirtualDecorator {
using type = T;
};
//! Remove virtual_<> decorator from a type (exposition only).
//! Removes the virtual_<> decorator (exposition only).
//!
//! Provides a nested `type` equal to `T`.
//!
//! @tparam T A type.
template<typename T>
struct StripVirtualDecorator<virtual_<T>> {
//! Same as `T`.
@@ -213,20 +220,20 @@ BOOST_OPENMETHOD_CLOSE_NAMESPACE_DETAIL_UNLESS_MRDOCS
// =============================================================================
// virtual_traits
//! Traits for types that can be used as virtual arguments.
//! Traits for types used as virtual parameters.
//!
//! `virtual_traits` must be specialized for each type that can be used as a
//! virtual parameters. It enables methods to:
//! @li find the type of the object the argument refers to (e.g. `Cat` from
//! `Cat&`)
//! @li obtain a non-modifiable reference to that object (e.g. a `const Cat&` from
//! `Cat&`)
//! @li cast the argument to another type (e.g. cast a `Animal&` to a `Cat&`)
//!
//! @li find the type of the object the argument refers to (e.g. `Node` from
//! `Node&`)
//! @li obtain a non-modifiable reference to that object (e.g. a `const Node&` from
//! `Node&`)
//! @li cast the argument to another type (e.g. cast a `Node&` to a `Plus&`)
//!
//! @par Requirements
//! Specializations of `virtual_traits` must implement the members deswcribed to the @ref VirtualTraits
//! blueprint.
//!
//! Specializations of `virtual_traits` must provide the members described to
//! the @ref VirtualTraits blueprint.
//!
//! @tparam T A type referring (in the broad sense) to an instance of a class.
//! @tparam Registry A @ref registry.
@@ -2067,20 +2074,19 @@ struct validate_method_parameter<
//!
//! `Registry` is an instantiation of class template @ref registry. Methods may
//! use only classes that have been registered in the same registry as virtual
//! parameters and arguments. The registry also policies that influence several
//! aspects of the dispatch mechanism - for example, how to obtain a v-table
//! pointer for an object, how to report errors, whether to perform sanity
//! checks, etc.
//! parameters and arguments. The registry also contains a set of policies that
//! influence several aspects of the dispatch mechanism - for example, how to
//! acquire a v-table pointer for an object, how to report errors, whether to
//! perform sanity checks, etc.
//!
//! The default value of `Registry` is the preprocessor symbol
//! `BOOST_OPENMETHOD_DEFAULT_REGISTRY`. It can be defined before including the
//! `<boost/openmethod/core.hpp>` header to override the default registry.
//! Setting this symbol after including `core.hpp` has no effect.
//! The default value for `Registry` is @ref default_registry, but it can be
//! overridden by defining the preprocessor symbol
//! {{BOOST_OPENMETHOD_DEFAULT_REGISTRY}}, *before* including
//! `<boost/openmethod/core.hpp>`. Setting the symbol afterwards has no effect.
//!
//! Specializations of `method` have a single instance: the static member `fn`,
//! a function object whose `operator()` is used to call the method and forward
//! to the appropriate overrider. It is selected in the same way as overloaded
//! function resolution:
//! which has an `operator()` that forwards to the appropriate overrider. It is
//! selected in the same way as overloaded function resolution:
//!
//! 1. Form the set of all applicable overriders. An overrider is applicable
//! if it can be called with the arguments passed to the method.
@@ -2088,8 +2094,8 @@ struct validate_method_parameter<
//! 2. If the set is empty, call the error handler (if present in the
//! registry), then terminate the program with `abort`.
//!
//! 3. Remove the overriders that are dominated by other overriders in the
//! set. Overrider A dominates overrider B if any of its virtual formal
//! 3. Remove the overriders that are dominated by other overriders in the set.
//! Overrider A dominates overrider B if at least one of its virtual formal
//! parameters is more specialized than B's, and if none of B's virtual
//! parameters is more specialized than A's.
//!
@@ -2806,6 +2812,9 @@ using boost::openmethod::virtual_ptr;
//!
//! Specializations of @ref virtual_traits must implement the members listed
//! here.
//!
//! @tparam T The type of a virtual parameter of a method.
//! @tparam Registry A @ref registry.
template<typename T, class Registry>
struct VirtualTraits {
//! Class to use for dispatch.
@@ -2817,6 +2826,11 @@ struct VirtualTraits {
//! `virtual_ptr<const Class>`, `std::shared_ptr<Class>`,
//! `std::shared_ptr<const Class>`, `virtual_ptr<std::shared_ptr<Class>>`,
//! etc.
//!
//! @par Requirements
//!
//! `virtual_type` must be an alias to an *unadorned* *class* type, *not*
//! cv-qualified.
using virtual_type = detail::unspecified;
//! Returns a reference to the object to use for dispatch.

View File

@@ -127,10 +127,11 @@ class static_list {
friend auto operator==(const iterator& a, const iterator& b) -> bool {
return a.ptr == b.ptr;
};
}
friend auto operator!=(const iterator& a, const iterator& b) -> bool {
return a.ptr != b.ptr;
};
}
private:
T* ptr;
@@ -179,11 +180,12 @@ class static_list {
friend auto
operator==(const const_iterator& a, const const_iterator& b) -> bool {
return a.ptr == b.ptr;
};
}
friend auto
operator!=(const const_iterator& a, const const_iterator& b) -> bool {
return a.ptr != b.ptr;
};
}
private:
T* ptr;

View File

@@ -1544,10 +1544,9 @@ void registry<Policies...>::compiler<Options...>::print(
//! Initialize a registry.
//!
//! Initialize the @ref registry passed as an explicit function template
//! Initialize the @ref registry passed as an explicit function template
//! argument, or @ref default_registry if the registry is not specified. The
//! default can be changed by defining
//! {{BOOST_OPENMETHOD_DEFAULT_REGISTRY}}.
//! default can be changed by defining {{BOOST_OPENMETHOD_DEFAULT_REGISTRY}}.
//! Option objects can be passed to change the behavior of the function.
//! Currently two options exist:
//! @li @ref trace Enable tracing of the initialization process.
@@ -1657,13 +1656,22 @@ auto registry<Policies...>::finalize(Options... opts) -> void {
initialized = false;
}
//! Finalize the default registry
inline auto finalize() -> void {
BOOST_OPENMETHOD_DEFAULT_REGISTRY::finalize();
}
namespace aliases {
using boost::openmethod::initialize;
//! Release resources held by registry.
//!
//! `finalize` may be called to release any resources allocated by
//! @ref registry::initialize.
//!
//! @note
//! A translation unit that contains a call to `finalize` must include the
//! `<boost/openmethod/initialize.hpp>` header.
//!
//! @tparam Registry The registry to finalize.
//! @tparam Options... Zero or more option types, deduced from the function
//! arguments.
//! @param options Zero or more option objects.
template<class Registry = BOOST_OPENMETHOD_DEFAULT_REGISTRY, class... Options>
inline auto finalize(Options&&... opts) -> void {
Registry::finalize(std::forward<Options>(opts)...);
}
} // namespace boost::openmethod

View File

@@ -62,8 +62,6 @@ struct va_args<ReturnType> {
::boost::openmethod::detail::va_args<__VA_ARGS__>::registry>
#define BOOST_OPENMETHOD(NAME, ARGS, ...) \
template<typename...> \
struct BOOST_OPENMETHOD_OVERRIDERS(NAME); \
struct BOOST_OPENMETHOD_ID(NAME); \
template<typename... ForwarderParameters> \
typename ::boost::openmethod::detail::enable_forwarder< \
@@ -72,14 +70,16 @@ struct va_args<ReturnType> {
ForwarderParameters...>::type \
BOOST_OPENMETHOD_GUIDE(NAME)(ForwarderParameters && ... args); \
template<typename... ForwarderParameters> \
inline auto NAME(ForwarderParameters&&... args) -> \
typename ::boost::openmethod::detail::enable_forwarder< \
inline auto NAME(ForwarderParameters&&... args) \
->typename ::boost::openmethod::detail::enable_forwarder< \
void, BOOST_OPENMETHOD_TYPE(NAME, ARGS, __VA_ARGS__), \
::boost::openmethod::detail::va_args<__VA_ARGS__>::return_type, \
ForwarderParameters...>::type { \
return BOOST_OPENMETHOD_TYPE(NAME, ARGS, __VA_ARGS__)::fn( \
std::forward<ForwarderParameters>(args)...); \
}
} \
template<typename...> \
struct BOOST_OPENMETHOD_OVERRIDERS(NAME)
#define BOOST_OPENMETHOD_DETAIL_LOCATE_METHOD(NAME, ARGS) \
template<typename T> \
@@ -88,7 +88,7 @@ struct va_args<ReturnType> {
struct boost_openmethod_detail_locate_method_aux<void(A...)> { \
using type = \
decltype(BOOST_OPENMETHOD_GUIDE(NAME)(std::declval<A>()...)); \
};
}
#define BOOST_OPENMETHOD_DECLARE_OVERRIDER(NAME, ARGS, ...) \
template<typename...> \
@@ -102,13 +102,15 @@ struct va_args<ReturnType> {
static auto next(Args&&... args) -> decltype(auto); \
}; \
inline auto BOOST_OPENMETHOD_OVERRIDERS( \
NAME)<__VA_ARGS__ ARGS>::has_next() -> bool { \
NAME)<__VA_ARGS__ ARGS>::has_next() \
->bool { \
return boost_openmethod_detail_locate_method_aux< \
void ARGS>::type::has_next<fn>(); \
} \
template<typename... Args> \
inline auto BOOST_OPENMETHOD_OVERRIDERS(NAME)<__VA_ARGS__ ARGS>::next( \
Args&&... args) -> decltype(auto) { \
Args&&... args) \
->decltype(auto) { \
return boost_openmethod_detail_locate_method_aux< \
void ARGS>::type::next<fn>(std::forward<Args>(args)...); \
}
@@ -123,7 +125,7 @@ struct va_args<ReturnType> {
#define BOOST_OPENMETHOD_DEFINE_OVERRIDER(NAME, ARGS, ...) \
BOOST_OPENMETHOD_DETAIL_REGISTER_OVERRIDER(NAME, ARGS, __VA_ARGS__) \
auto BOOST_OPENMETHOD_OVERRIDER(NAME, ARGS, __VA_ARGS__)::fn ARGS \
-> boost::mp11::mp_back<boost::mp11::mp_list<__VA_ARGS__>>
->boost::mp11::mp_back<boost::mp11::mp_list<__VA_ARGS__>>
#define BOOST_OPENMETHOD_OVERRIDE(NAME, ARGS, ...) \
BOOST_OPENMETHOD_DECLARE_OVERRIDER(NAME, ARGS, __VA_ARGS__) \
@@ -133,9 +135,9 @@ struct va_args<ReturnType> {
BOOST_OPENMETHOD_DECLARE_OVERRIDER(NAME, ARGS, __VA_ARGS__) \
BOOST_OPENMETHOD_DETAIL_REGISTER_OVERRIDER(NAME, ARGS, __VA_ARGS__) \
inline auto BOOST_OPENMETHOD_OVERRIDER(NAME, ARGS, __VA_ARGS__)::fn ARGS \
-> boost::mp11::mp_back<boost::mp11::mp_list<__VA_ARGS__>>
->boost::mp11::mp_back<boost::mp11::mp_list<__VA_ARGS__>>
#define BOOST_OPENMETHOD_CLASSES(...) \
BOOST_OPENMETHOD_REGISTER(::boost::openmethod::use_classes<__VA_ARGS__>);
BOOST_OPENMETHOD_REGISTER(::boost::openmethod::use_classes<__VA_ARGS__>)
#endif

View File

@@ -183,7 +183,7 @@ struct vptr_vector : vptr {
} else {
detail::vptr_vector_vptrs<Registry>.clear();
}
};
}
};
};

View File

@@ -376,12 +376,19 @@ struct unspecified {};
//! Blueprint for a lightweight output stream (exposition only).
//!
//! Classes used as output streams in policies must provide the free functions
//! described on this page.
//! Classes used as output streams in policies must provide the operations
//! described on this page, either as members or as free functions.
struct LightweightOutputStream {
//! Writes a null-terminated string to the stream.
LightweightOutputStream& operator<<(const char* str);
//! Writes a string view to the stream.
LightweightOutputStream& operator<<(const std::string_view& view);
//! Writes a pointer value to the stream.
LightweightOutputStream& operator<<(const void* value);
//! Writes a size_t value to the stream.
LightweightOutputStream& operator<<(std::size_t value);
};
@@ -662,9 +669,9 @@ struct VptrFn {
//!
//! @tparam Options... Zero or more option types, deduced from the
//! function arguments.
//! @param options Zero or more option objects.
//! @param options A tuple of option objects.
template<class... Options>
static auto finalize(std::tuple<Options...> opts) -> void;
static auto finalize(const std::tuple<Options...>& options) -> void;
};
#endif
@@ -704,17 +711,12 @@ template<class Registry>
struct TypeHashFn {
//! Initialize the hash table.
//!
//! @tparam ForwardIterator An iterator to a range of @ref
//! InitializeClass objects.
//! @tparam Options... Zero or more option types, deduced from the
//! function arguments.
//! @param first An iterator to the beginning of the range.
//! @param last An iterator to the end of the range.
//! @param options Zero or more option objects.
//! @tparam Context A class that conforms to the @ref InitializeContext
//! blueprint.
//! @return A pair containing the minimum and maximum hash values.
template<typename ForwardIterator>
static auto initialize(ForwardIterator first, ForwardIterator last)
-> std::pair<std::size_t, std::size_t>;
template<class Context>
static auto
initialize(const Context& ctx) -> std::pair<std::size_t, std::size_t>;
//! Hash a `type_id`.
//!
@@ -726,10 +728,11 @@ struct TypeHashFn {
//!
//! This function is optional.
//!
//! @tparam Options... Zero or more option types, deduced from the function
//! arguments.
//! @param options Zero or more option objects.
static auto finalize() -> void;
//! @tparam Options... Zero or more option types, deduced from the
//! function arguments.
//! @param options A tuple of option objects.
template<class... Options>
static auto finalize(const std::tuple<Options...>& options) -> void;
};
#endif
@@ -933,8 +936,6 @@ class registry : detail::registry_base {
template<class... Options>
struct compiler;
// template<class Registry, typename... Options>
// friend compiler<Options...> initialize(Options...);
//! Check that the registry is initialized.
//!
@@ -946,16 +947,6 @@ class registry : detail::registry_base {
//! @li @ref not_initialized: The registry is not initialized.
static void require_initialized();
//! Releases the resources held by the registry.
//!
//! `finalize` may be called to release any resources allocated by
//! @ref registry::initialize.
//!
//! @note
//! A translation unit that contains a call to `finalize` must include the
//! `<boost/openmethod/initialize.hpp>` header.
//!
//! @tparam Options A registry.
template<class... Options>
static void finalize(Options... opts);

View File

@@ -7,10 +7,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
<html>
<head>
<meta http-equiv="refresh" content="0; URL=doc/html/index.html">
<meta http-equiv="refresh" content="0; URL=doc/html/openmethod/index.html">
</head>
<body>
Automatic redirection failed, please go to
<a href="doc/html/index.html">doc/html/index.html</a>
<a href="doc/html/openmethod/index.html">doc/html/openmethod/index.html</a>
</body>
</html>

View File

@@ -7,9 +7,9 @@
"maintainers": [
"Jean-Louis Leroy"
],
"description": "Open methods for C++17 and above.",
"description": "Open-methods are free-standing functions that work like virtual functions: they select the best overrider from a set, depending on the dynamic type of their arguments. This makes it possible to add polymorphic operations to existing classes, without modifying them. They make patterns like Visitor unnecessary.",
"category": [
"Programming"
"Emulation", "Programming"
],
"cxxstd": "17"
}

View File

@@ -339,7 +339,7 @@ BOOST_AUTO_TEST_CASE(simple) {
if constexpr (std::is_same_v<test_registry::vptr, policies::vptr_vector>) {
BOOST_TEST(
!detail::vptr_vector_vptrs<test_registry::registry_type>.empty());
test_registry::finalize();
finalize<test_registry>();
static_assert(detail::has_finalize_aux<
void, test_registry::policy<policies::vptr>,
std::tuple<>>::value);

View File

@@ -186,11 +186,14 @@ namespace non_polymorphic {
struct Animal {}; // polymorphic not required
struct Dog : Animal {}; // polymorphic not required
BOOST_OPENMETHOD_CLASSES(Animal, Dog);
// codecov:ignore:start
BOOST_OPENMETHOD(poke, (virtual_ptr<Animal>), void);
void instiantiate_poke(virtual_ptr<Dog> snoopy) {
void instantiate_poke(virtual_ptr<Dog> snoopy) {
poke(snoopy);
}
// codecov:ignore:end
BOOST_AUTO_TEST_CASE(virtual_ptr_examples_non_polymorphic) {
{