mirror of
https://github.com/boostorg/openmethod.git
synced 2026-01-21 05:02:14 +00:00
Compare commits
19 Commits
boost-1.90
...
fix/coveri
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55b8c07a57 | ||
|
|
6fdbfb361a | ||
|
|
f0a8656744 | ||
|
|
c465260fe7 | ||
|
|
f53122eae8 | ||
|
|
41eaec5bef | ||
|
|
5796d3c3ea | ||
|
|
a6337d2f55 | ||
|
|
02cffffe4f | ||
|
|
ef48e48235 | ||
|
|
e0ead3bf71 | ||
|
|
764c0b9237 | ||
|
|
c64960d6c8 | ||
|
|
48e85546ce | ||
|
|
8933eb3b4f | ||
|
|
b8da0a1088 | ||
|
|
4d91aab7fd | ||
|
|
dac3cf7087 | ||
|
|
52fa71306e |
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -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
|
||||
|
||||
@@ -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})
|
||||
@@ -67,21 +92,30 @@ set(
|
||||
Boost::preprocessor
|
||||
)
|
||||
|
||||
if (BOOST_OPENMETHOD_BUILD_TESTS OR BOOST_OPENMETHOD_MRDOCS_BUILD)
|
||||
list(APPEND BOOST_OPENMETHOD_DEPENDENCIES Boost::smart_ptr)
|
||||
endif()
|
||||
|
||||
foreach (BOOST_OPENMETHOD_DEPENDENCY ${BOOST_OPENMETHOD_DEPENDENCIES})
|
||||
if (BOOST_OPENMETHOD_DEPENDENCY MATCHES "^[ ]*Boost::([A-Za-z0-9_]+)[ ]*$")
|
||||
list(APPEND BOOST_OPENMETHOD_INCLUDE_LIBRARIES ${CMAKE_MATCH_1})
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
# Conditional dependencies
|
||||
if (BOOST_OPENMETHOD_MRDOCS_BUILD)
|
||||
list(APPEND BOOST_OPENMETHOD_INCLUDE_LIBRARIES smart_ptr)
|
||||
endif()
|
||||
|
||||
if (NOT BOOST_OPENMETHOD_MRDOCS_BUILD)
|
||||
if (BUILD_TESTING OR BOOST_OPENMETHOD_BUILD_TESTS)
|
||||
if (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
|
||||
set(BOOST_INCLUDE_LIBRARIES ${BOOST_OPENMETHOD_INCLUDE_LIBRARIES} ${BOOST_OPENMETHOD_UNIT_TEST_LIBRARIES} ${BOOST_OPENMETHOD_EXAMPLE_LIBRARIES})
|
||||
set(BOOST_EXCLUDE_LIBRARIES openmethod)
|
||||
@@ -175,20 +209,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 ()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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{{{(.*?)}}}{<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"
|
||||
|
||||
@@ -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 they’ve 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 couldn’t 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 don’t 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++ 2006–2020).
|
||||
|
||||
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.
|
||||
@@ -3,146 +3,153 @@
|
||||
// See accompanying file LICENSE_1_0.txt
|
||||
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// https://godbolt.org/z/r6o4f171r
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
|
||||
#include <boost/openmethod.hpp>
|
||||
#include <boost/openmethod/policies/static_rtti.hpp>
|
||||
#include <boost/openmethod/initialize.hpp>
|
||||
#include <boost/openmethod/interop/std_shared_ptr.hpp>
|
||||
|
||||
using std::make_shared;
|
||||
using std::shared_ptr;
|
||||
using std::string;
|
||||
|
||||
using boost::openmethod::make_shared_virtual;
|
||||
using boost::openmethod::shared_virtual_ptr;
|
||||
using boost::openmethod::virtual_ptr;
|
||||
using namespace boost::openmethod::aliases;
|
||||
|
||||
struct matrix {
|
||||
virtual ~matrix() {
|
||||
}
|
||||
virtual auto at(int row, int col) const -> double = 0;
|
||||
// ...
|
||||
struct abstract {
|
||||
int ref_count = 0;
|
||||
};
|
||||
|
||||
struct dense_matrix : matrix {
|
||||
virtual auto at(int /*row*/, int /*col*/) const -> double {
|
||||
return 0;
|
||||
struct registry
|
||||
: boost::openmethod::registry<boost::openmethod::policies::static_rtti> {};
|
||||
|
||||
template<class Rep>
|
||||
using matrix_ptr = boost::openmethod::virtual_ptr<Rep, registry>;
|
||||
|
||||
BOOST_OPENMETHOD(destroy, (matrix_ptr<abstract>), void, registry);
|
||||
|
||||
class matrix {
|
||||
matrix_ptr<abstract> rep_;
|
||||
|
||||
explicit matrix(matrix_ptr<abstract> rep) : rep_(rep) {
|
||||
++rep_->ref_count;
|
||||
|
||||
if (--rep->ref_count == 0) {
|
||||
destroy(rep);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
matrix(const matrix&) = default;
|
||||
matrix& operator=(const matrix&) = default;
|
||||
|
||||
auto rep() const -> matrix_ptr<abstract> {
|
||||
return rep_;
|
||||
}
|
||||
|
||||
template<class Rep, class... Args>
|
||||
static matrix make(Args&&... args) {
|
||||
return matrix(
|
||||
boost::openmethod::final_virtual_ptr<registry>(
|
||||
*new Rep(std::forward<Args>(args)...)));
|
||||
}
|
||||
};
|
||||
|
||||
struct diagonal_matrix : matrix {
|
||||
virtual auto at(int /*row*/, int /*col*/) const -> double {
|
||||
return 0;
|
||||
}
|
||||
struct dense : abstract {
|
||||
static constexpr const char* type = "dense";
|
||||
};
|
||||
|
||||
BOOST_OPENMETHOD_CLASSES(matrix, dense_matrix, diagonal_matrix);
|
||||
|
||||
BOOST_OPENMETHOD(to_json, (virtual_ptr<const matrix>), string);
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(to_json, (virtual_ptr<const dense_matrix>), string) {
|
||||
return "json for dense matrix...";
|
||||
BOOST_OPENMETHOD_OVERRIDE(destroy, (matrix_ptr<dense> rep), void) {
|
||||
delete rep.get();
|
||||
}
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(
|
||||
to_json, (virtual_ptr<const diagonal_matrix>), string) {
|
||||
return "json for diagonal matrix...";
|
||||
struct diagonal : abstract {
|
||||
static constexpr const char* type = "diagonal";
|
||||
};
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(destroy, (matrix_ptr<diagonal> rep), void) {
|
||||
delete rep.get();
|
||||
}
|
||||
|
||||
BOOST_OPENMETHOD_CLASSES(abstract, dense, diagonal, registry);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// matrix * matrix
|
||||
|
||||
BOOST_OPENMETHOD(
|
||||
times, (shared_virtual_ptr<const matrix>, shared_virtual_ptr<const matrix>),
|
||||
shared_virtual_ptr<const matrix>);
|
||||
times, (matrix_ptr<abstract>, matrix_ptr<abstract>), matrix, registry);
|
||||
|
||||
// catch-all matrix * matrix -> dense_matrix
|
||||
// catch-all matrix * matrix -> dense
|
||||
BOOST_OPENMETHOD_OVERRIDE(
|
||||
times,
|
||||
(shared_virtual_ptr<const matrix> /*a*/,
|
||||
shared_virtual_ptr<const matrix> /*b*/),
|
||||
shared_virtual_ptr<const dense_matrix>) {
|
||||
return make_shared<const dense_matrix>();
|
||||
times, (matrix_ptr<abstract> /*a*/, matrix_ptr<abstract> /*b*/), matrix) {
|
||||
return matrix::make<dense>();
|
||||
}
|
||||
|
||||
// diagonal_matrix * diagonal_matrix -> diagonal_matrix
|
||||
// diagonal * diagonal -> diagonal
|
||||
BOOST_OPENMETHOD_OVERRIDE(
|
||||
times,
|
||||
(shared_virtual_ptr<const diagonal_matrix> /*a*/,
|
||||
shared_virtual_ptr<const diagonal_matrix> /*b*/),
|
||||
shared_virtual_ptr<const diagonal_matrix>) {
|
||||
return make_shared_virtual<diagonal_matrix>();
|
||||
times, (matrix_ptr<diagonal> /*a*/, matrix_ptr<diagonal> /*b*/), matrix) {
|
||||
return matrix::make<diagonal>();
|
||||
}
|
||||
|
||||
inline auto operator*(shared_ptr<const matrix> a, shared_ptr<const matrix> b)
|
||||
-> shared_virtual_ptr<const matrix> {
|
||||
return times(a, b);
|
||||
inline auto operator*(matrix a, matrix b) -> matrix {
|
||||
return times(a.rep(), b.rep());
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// scalar * matrix
|
||||
|
||||
BOOST_OPENMETHOD(
|
||||
times, (double, shared_virtual_ptr<const matrix>),
|
||||
shared_virtual_ptr<const matrix>);
|
||||
BOOST_OPENMETHOD(times, (double, matrix_ptr<abstract>), matrix, registry);
|
||||
|
||||
// catch-all matrix * scalar -> dense_matrix
|
||||
// catch-all matrix * scalar -> dense
|
||||
BOOST_OPENMETHOD_OVERRIDE(
|
||||
times, (double /*a*/, shared_virtual_ptr<const matrix> /*b*/),
|
||||
shared_virtual_ptr<const dense_matrix>) {
|
||||
return make_shared_virtual<dense_matrix>();
|
||||
times, (double /*a*/, matrix_ptr<abstract> /*b*/), matrix) {
|
||||
return matrix::make<dense>();
|
||||
}
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(
|
||||
times, (double /*a*/, shared_virtual_ptr<const diagonal_matrix> /*b*/),
|
||||
shared_virtual_ptr<const diagonal_matrix>) {
|
||||
return make_shared_virtual<diagonal_matrix>();
|
||||
times, (double /*a*/, matrix_ptr<diagonal> /*b*/), matrix) {
|
||||
return matrix::make<diagonal>();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// matrix * scalar
|
||||
|
||||
// just swap
|
||||
inline auto times(shared_virtual_ptr<const matrix> a, double b)
|
||||
-> shared_virtual_ptr<const matrix> {
|
||||
inline auto times(matrix_ptr<abstract> a, double b) -> matrix {
|
||||
return times(b, a);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// main
|
||||
|
||||
#define check(expr) \
|
||||
{ \
|
||||
if (!(expr)) { \
|
||||
cerr << #expr << " failed\n"; \
|
||||
} \
|
||||
}
|
||||
BOOST_OPENMETHOD(write, (matrix_ptr<abstract>), string, registry);
|
||||
|
||||
inline auto operator<<(std::ostream& os, matrix a) -> std::ostream& {
|
||||
return os << write(a.rep());
|
||||
}
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(write, (matrix_ptr<dense>), string) {
|
||||
return "a dense matrix";
|
||||
}
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(write, (matrix_ptr<diagonal>), string) {
|
||||
return "a diagonal matrix";
|
||||
}
|
||||
|
||||
auto main() -> int {
|
||||
using std::cerr;
|
||||
using std::cout;
|
||||
|
||||
boost::openmethod::initialize();
|
||||
boost::openmethod::initialize<registry>();
|
||||
|
||||
shared_ptr<const matrix> a = make_shared<dense_matrix>();
|
||||
shared_ptr<const matrix> b = make_shared<diagonal_matrix>();
|
||||
matrix a = matrix::make<dense>();
|
||||
matrix b = matrix::make<diagonal>();
|
||||
double s = 1;
|
||||
|
||||
#ifdef BOOST_CLANG
|
||||
#pragma clang diagnostic ignored "-Wpotentially-evaluated-expression"
|
||||
#endif
|
||||
|
||||
check(typeid(*times(a, a)) == typeid(dense_matrix));
|
||||
check(typeid(*times(a, b)) == typeid(dense_matrix));
|
||||
check(typeid(*times(b, b)) == typeid(diagonal_matrix));
|
||||
check(typeid(*times(s, a)) == typeid(dense_matrix));
|
||||
check(typeid(*times(s, b)) == typeid(diagonal_matrix));
|
||||
|
||||
cout << to_json(*a) << "\n"; // json for dense matrix
|
||||
cout << to_json(*b) << "\n"; // json for diagonal matrix
|
||||
cout << a << "\n";
|
||||
cout << b << "\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
150
doc/modules/ROOT/examples/matrix_intrusive_vptr.cpp
Normal file
150
doc/modules/ROOT/examples/matrix_intrusive_vptr.cpp
Normal file
@@ -0,0 +1,150 @@
|
||||
// Copyright (c) 2018-2025 Jean-Louis Leroy
|
||||
// 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)
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
|
||||
#include <boost/openmethod.hpp>
|
||||
#include <boost/openmethod/initialize.hpp>
|
||||
#include <boost/openmethod/interop/boost_intrusive_ptr.hpp>
|
||||
|
||||
using std::string;
|
||||
|
||||
using namespace boost::openmethod::aliases;
|
||||
|
||||
struct abstract {
|
||||
virtual ~abstract() {
|
||||
}
|
||||
|
||||
int ref_count = 0;
|
||||
|
||||
friend void intrusive_ptr_add_ref(abstract* p) {
|
||||
++p->ref_count;
|
||||
}
|
||||
|
||||
friend void intrusive_ptr_release(abstract* p) {
|
||||
if (--p->ref_count == 0) {
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<class Rep>
|
||||
using matrix_ptr = boost::openmethod::boost_intrusive_virtual_ptr<Rep>;
|
||||
|
||||
class matrix {
|
||||
matrix_ptr<abstract> rep_;
|
||||
|
||||
explicit matrix(matrix_ptr<abstract> rep) : rep_(rep) {
|
||||
}
|
||||
|
||||
public:
|
||||
matrix(const matrix&) = default;
|
||||
matrix& operator=(const matrix&) = default;
|
||||
|
||||
auto rep() const -> matrix_ptr<abstract> {
|
||||
return rep_;
|
||||
}
|
||||
|
||||
template<class Rep>
|
||||
static matrix make() {
|
||||
return matrix(boost::openmethod::make_boost_intrusive_virtual<Rep>());
|
||||
}
|
||||
};
|
||||
|
||||
struct dense : abstract {};
|
||||
|
||||
struct diagonal : abstract {};
|
||||
|
||||
using namespace boost::openmethod::aliases;
|
||||
|
||||
BOOST_OPENMETHOD_CLASSES(abstract, dense, diagonal);
|
||||
|
||||
BOOST_OPENMETHOD(to_str, (matrix_ptr<abstract>), string);
|
||||
|
||||
inline auto operator<<(std::ostream& os, matrix a) -> std::ostream& {
|
||||
return os << to_str(a.rep());
|
||||
}
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(to_str, (matrix_ptr<dense>), string) {
|
||||
return "a dense matrix";
|
||||
}
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(to_str, (matrix_ptr<diagonal>), string) {
|
||||
return "a diagonal matrix";
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// matrix * matrix
|
||||
|
||||
BOOST_OPENMETHOD(times, (matrix_ptr<abstract>, matrix_ptr<abstract>), matrix);
|
||||
|
||||
// catch-all matrix * matrix -> dense
|
||||
BOOST_OPENMETHOD_OVERRIDE(
|
||||
times, (matrix_ptr<abstract> /*a*/, matrix_ptr<abstract> /*b*/), matrix) {
|
||||
return matrix::make<dense>();
|
||||
}
|
||||
|
||||
// diagonal * diagonal -> diagonal
|
||||
BOOST_OPENMETHOD_OVERRIDE(
|
||||
times, (matrix_ptr<diagonal> /*a*/, matrix_ptr<diagonal> /*b*/), matrix) {
|
||||
return matrix::make<diagonal>();
|
||||
}
|
||||
|
||||
inline auto operator*(matrix a, matrix b) -> matrix {
|
||||
return times(a.rep(), b.rep());
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// scalar * matrix
|
||||
|
||||
BOOST_OPENMETHOD(times, (double, matrix_ptr<abstract>), matrix);
|
||||
|
||||
// catch-all matrix * scalar -> dense
|
||||
BOOST_OPENMETHOD_OVERRIDE(
|
||||
times, (double /*a*/, matrix_ptr<abstract> /*b*/), matrix) {
|
||||
return matrix::make<dense>();
|
||||
}
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(
|
||||
times, (double /*a*/, matrix_ptr<diagonal> /*b*/), matrix) {
|
||||
return matrix::make<diagonal>();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// matrix * scalar
|
||||
|
||||
// just swap
|
||||
inline auto times(matrix_ptr<abstract> a, double b) -> matrix {
|
||||
return times(b, a);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// main
|
||||
|
||||
#define check(expr) \
|
||||
{ \
|
||||
if (!(expr)) { \
|
||||
cerr << #expr << " failed\n"; \
|
||||
} \
|
||||
}
|
||||
|
||||
auto main() -> int {
|
||||
using std::cerr;
|
||||
using std::cout;
|
||||
|
||||
boost::openmethod::initialize();
|
||||
|
||||
matrix a = matrix::make<dense>();
|
||||
matrix b = matrix::make<diagonal>();
|
||||
double s = 1;
|
||||
|
||||
cout << a << "\n";
|
||||
cout << b << "\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -14,5 +14,5 @@ BOOST_OPENMETHOD_OVERRIDE(
|
||||
return 5000.0;
|
||||
}
|
||||
|
||||
BOOST_OPENMETHOD_CLASSES(Employee)
|
||||
BOOST_OPENMETHOD_CLASSES(Employee);
|
||||
// end::content[]
|
||||
|
||||
@@ -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[]
|
||||
|
||||
@@ -12,5 +12,5 @@ BOOST_OPENMETHOD_DEFINE_OVERRIDER(
|
||||
return 5000.0;
|
||||
}
|
||||
|
||||
BOOST_OPENMETHOD_CLASSES(Employee)
|
||||
BOOST_OPENMETHOD_CLASSES(Employee);
|
||||
// end::content[]
|
||||
|
||||
@@ -16,4 +16,4 @@ BOOST_OPENMETHOD_OVERRIDE(
|
||||
}
|
||||
// end::content[]
|
||||
|
||||
BOOST_OPENMETHOD_CLASSES(Employee, Salesman)
|
||||
BOOST_OPENMETHOD_CLASSES(Employee, Salesman);
|
||||
|
||||
@@ -7,5 +7,5 @@
|
||||
#include "roles.hpp"
|
||||
#include <boost/openmethod.hpp>
|
||||
|
||||
BOOST_OPENMETHOD_CLASSES(Employee)
|
||||
BOOST_OPENMETHOD_CLASSES(Employee);
|
||||
// end::content[]
|
||||
|
||||
@@ -16,4 +16,4 @@ BOOST_OPENMETHOD_OVERRIDE(
|
||||
}
|
||||
// end::content[]
|
||||
|
||||
BOOST_OPENMETHOD_CLASSES(Employee, Salesman)
|
||||
BOOST_OPENMETHOD_CLASSES(Employee, Salesman);
|
||||
|
||||
@@ -7,5 +7,5 @@
|
||||
#include "roles.hpp"
|
||||
#include <boost/openmethod.hpp>
|
||||
|
||||
BOOST_OPENMETHOD_CLASSES(employees::Employee)
|
||||
BOOST_OPENMETHOD_CLASSES(employees::Employee);
|
||||
// end::content[]
|
||||
|
||||
@@ -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[]
|
||||
|
||||
@@ -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[]
|
||||
|
||||
@@ -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[]
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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>())
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
= xref:macros.adoc[Macro] BOOST_OPENMETHOD_DEFAULT_REGISTRY
|
||||
# BOOST_OPENMETHOD_DEFAULT_REGISTRY
|
||||
|
||||
Default value for Registry
|
||||
|
||||
|
||||
@@ -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].
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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++]
|
||||
----
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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++]
|
||||
----
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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++]
|
||||
----
|
||||
|
||||
@@ -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++]
|
||||
----
|
||||
|
||||
@@ -7,21 +7,70 @@
|
||||
|
||||
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.
|
||||
|
||||
[#boost_intrusive_ptr]
|
||||
### link:{{BASE_URL}}/include/boost/openmethod/interop/boost_intrusive_ptr.hpp[<boost/openmethod/interop/boost_intrusive_ptr.hpp>]
|
||||
|
||||
Provides a `virtual_traits` specialization that makes it possible to use a
|
||||
`boost::intrusive_ptr` in place of a raw pointer or reference in virtual parameters.
|
||||
|
||||
*The headers below are for advanced use*.
|
||||
|
||||
## Pre-Core Headers
|
||||
@@ -30,82 +79,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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
599
doc/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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...&& 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...&& 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...&& args)</arglist>
|
||||
</member>
|
||||
<member kind="function">
|
||||
<type>bool</type>
|
||||
<name>operator==</name>
|
||||
<anchorfile>boost/openmethod/operator_eq.adoc</anchorfile>
|
||||
<anchor/>
|
||||
<arglist>(const virtual_ptr<Left, Registry>& left, const virtual_ptr<Right, Registry>& 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<Left, Registry>& left, const virtual_ptr<Right, Registry>& 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& 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&</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& 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& 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&& 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<std::size_t, std::size_t></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<Options...> opts)</arglist>
|
||||
</member>
|
||||
<member kind="function">
|
||||
<type>const vptr_type&</type>
|
||||
<name>dynamic_vptr</name>
|
||||
<anchorfile>boost/openmethod/policies/VptrFn/dynamic_vptr.adoc</anchorfile>
|
||||
<anchor/>
|
||||
<arglist>(const Class& arg)</arglist>
|
||||
</member>
|
||||
<member kind="function">
|
||||
<type>void</type>
|
||||
<name>finalize</name>
|
||||
<anchorfile>boost/openmethod/policies/VptrFn/finalize.adoc</anchorfile>
|
||||
<anchor/>
|
||||
<arglist>(std::tuple<Options...> 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&</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& 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& 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<Parameters>::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& 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& 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& 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& 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& 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-></name>
|
||||
<anchorfile>boost/openmethod/virtual_ptr-0a/operator_ptr.adoc</anchorfile>
|
||||
<anchor/>
|
||||
<arglist>()</arglist>
|
||||
</member>
|
||||
<member kind="function">
|
||||
<type>element_type&</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&& 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-></name>
|
||||
<anchorfile>boost/openmethod/virtual_ptr-0b5/operator_ptr.adoc</anchorfile>
|
||||
<anchor/>
|
||||
<arglist>()</arglist>
|
||||
</member>
|
||||
<member kind="function">
|
||||
<type>element_type&</type>
|
||||
<name>operator*</name>
|
||||
<anchorfile>boost/openmethod/virtual_ptr-0b5/operator_star.adoc</anchorfile>
|
||||
<anchor/>
|
||||
<arglist>()</arglist>
|
||||
</member>
|
||||
<member kind="function">
|
||||
<type>const SmartPtr&</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&& 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&</type>
|
||||
<name>peek</name>
|
||||
<anchorfile>boost/openmethod/virtual_traits-043/peek.adoc</anchorfile>
|
||||
<anchor/>
|
||||
<arglist>(const std::shared_ptr<Class>& 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&</type>
|
||||
<name>peek</name>
|
||||
<anchorfile>boost/openmethod/virtual_traits-0bf/peek.adoc</anchorfile>
|
||||
<anchor/>
|
||||
<arglist>(const std::unique_ptr<Class>& 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<Class>&& 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<Class, Registry>&</type>
|
||||
<name>peek</name>
|
||||
<anchorfile>boost/openmethod/virtual_traits-096/peek.adoc</anchorfile>
|
||||
<anchor/>
|
||||
<arglist>(const virtual_ptr<Class, Registry>& 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&</type>
|
||||
<name>peek</name>
|
||||
<anchorfile>boost/openmethod/virtual_traits-08/peek.adoc</anchorfile>
|
||||
<anchor/>
|
||||
<arglist>(const Class& arg)</arglist>
|
||||
</member>
|
||||
<member kind="function">
|
||||
<type>Derived</type>
|
||||
<name>cast</name>
|
||||
<anchorfile>boost/openmethod/virtual_traits-08/cast.adoc</anchorfile>
|
||||
<anchor/>
|
||||
<arglist>(Class& 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&</type>
|
||||
<name>peek</name>
|
||||
<anchorfile>boost/openmethod/virtual_traits-07a/peek.adoc</anchorfile>
|
||||
<anchor/>
|
||||
<arglist>(const std::shared_ptr<Class>& 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<Class>& 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<Class, Registry>&</type>
|
||||
<name>peek</name>
|
||||
<anchorfile>boost/openmethod/virtual_traits-048/peek.adoc</anchorfile>
|
||||
<anchor/>
|
||||
<arglist>(const virtual_ptr<Class, Registry>& 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<Class, Registry>& 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&</type>
|
||||
<name>peek</name>
|
||||
<anchorfile>boost/openmethod/virtual_traits-098/peek.adoc</anchorfile>
|
||||
<anchor/>
|
||||
<arglist>(const Class& arg)</arglist>
|
||||
</member>
|
||||
<member kind="function">
|
||||
<type>Derived</type>
|
||||
<name>cast</name>
|
||||
<anchorfile>boost/openmethod/virtual_traits-098/cast.adoc</anchorfile>
|
||||
<anchor/>
|
||||
<arglist>(Class&& 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&</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>
|
||||
@@ -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.
|
||||
@@ -2830,14 +2844,21 @@ struct VirtualTraits {
|
||||
|
||||
//! Casts a virtual argument.
|
||||
//!
|
||||
//! Casts a virtual argument to the type expected by the overrider.
|
||||
//! `cast` is responsible for passing virtual arguments from method to
|
||||
//! overrider. In general, this requires some form of adjustment, because a
|
||||
//! virtual parameter in the overrider usually has a different type than the
|
||||
//! corresponding parameter in the method. Typically, the adjustment
|
||||
//! consists of a cast, performed via `static_cast`, `dynamic_cast`, or
|
||||
//! other means, depending on the type of the argument and the rtti policy
|
||||
//! of the method. `cast` may return the adjusted argument by reference or
|
||||
//! as a temporary value.
|
||||
//!
|
||||
//! @tparam T The type of a virtual parameter of a method.
|
||||
//! @tparam U The type of a virtual parameter of an overrider.
|
||||
//! @param arg The argument passed to a method call.
|
||||
//! @return A reference to the argument, cast to `U`.
|
||||
//! @tparam T The type of the virtual parameter in the method.
|
||||
//! @tparam U The type of the virtual parameter in the overrider.
|
||||
//! @param arg The argument passed to the method call.
|
||||
//! @return A value that can be passed as a U.
|
||||
template<typename U>
|
||||
static auto cast(T arg) -> U;
|
||||
static auto cast(T arg) -> detail::unspecified;
|
||||
|
||||
//! Rebind to a another class (smart pointers only).
|
||||
//!
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <cstdio>
|
||||
#include <charconv>
|
||||
#include <random>
|
||||
#include <string_view>
|
||||
|
||||
namespace boost::openmethod {
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
150
include/boost/openmethod/interop/boost_intrusive_ptr.hpp
Normal file
150
include/boost/openmethod/interop/boost_intrusive_ptr.hpp
Normal file
@@ -0,0 +1,150 @@
|
||||
// Copyright (c) 2018-2025 Jean-Louis Leroy
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_OPENMETHOD_INTEROP_BOOST_INTRUSIVE_PTR_HPP
|
||||
#define BOOST_OPENMETHOD_INTEROP_BOOST_INTRUSIVE_PTR_HPP
|
||||
|
||||
#include <boost/openmethod/core.hpp>
|
||||
#include <boost/smart_ptr/intrusive_ptr.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace boost::openmethod {
|
||||
|
||||
//! Specialize virtual_traits for boost::intrusive_ptr.
|
||||
//!
|
||||
//! @tparam Class A class type, possibly cv-qualified.
|
||||
//! @tparam Registry A @ref registry.
|
||||
template<typename Class, class Registry>
|
||||
struct virtual_traits<boost::intrusive_ptr<Class>, Registry> {
|
||||
//! Rebind to a different element type.
|
||||
//!
|
||||
//! @tparam Other The new element type.
|
||||
template<class Other>
|
||||
using rebind = boost::intrusive_ptr<Other>;
|
||||
|
||||
//! `Class`, stripped from cv-qualifiers.
|
||||
using virtual_type = std::remove_cv_t<Class>;
|
||||
|
||||
//! Return a reference to a non-modifiable `Class` object.
|
||||
//! @param arg A reference to a `boost::intrusive_ptr<Class>`.
|
||||
//! @return A reference to the object pointed to.
|
||||
static auto peek(const boost::intrusive_ptr<Class>& arg) -> const Class& {
|
||||
return *arg;
|
||||
}
|
||||
|
||||
//! Cast method argument to overrider argument.
|
||||
//!
|
||||
//! Cast a `boost::intrusive_ptr` to a `boost::intrusive_ptr` to a derived
|
||||
//! class, using a static cast if possible, and a dynamic cast otherwise.
|
||||
//!
|
||||
//! @tparam OverriderType The type required by the overrider (a
|
||||
//! `boost::intrusive_ptr`).
|
||||
//! @param obj The method's argument..
|
||||
//! @return A `boost::intrusive_ptr` _value_.
|
||||
template<class OverriderType>
|
||||
static auto cast(const boost::intrusive_ptr<Class>& obj) {
|
||||
using element_type = typename OverriderType::element_type;
|
||||
|
||||
if constexpr (detail::requires_dynamic_cast<Class*, element_type*>) {
|
||||
// make it work with custom RTTI
|
||||
return OverriderType(
|
||||
&Registry::rtti::template dynamic_cast_ref<element_type&>(
|
||||
*obj));
|
||||
} else {
|
||||
return boost::static_pointer_cast<element_type>(obj);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//! Specialize virtual_traits for const boost::intrusive_ptr&.
|
||||
//!
|
||||
//! @tparam Class A class type, possibly cv-qualified.
|
||||
//! @tparam Registry A @ref registry.
|
||||
template<class Class, class Registry>
|
||||
struct virtual_traits<const boost::intrusive_ptr<Class>&, Registry> {
|
||||
public:
|
||||
//! Rebind to a different element type.
|
||||
//!
|
||||
//! @tparam Other The new element type.
|
||||
template<class Other>
|
||||
using rebind = boost::intrusive_ptr<Other>;
|
||||
|
||||
//! `Class`, stripped from cv-qualifiers.
|
||||
using virtual_type = std::remove_cv_t<Class>;
|
||||
|
||||
//! Return a reference to a non-modifiable `Class` object.
|
||||
//! @param arg A reference to a `boost::intrusive_ptr<Class>`.
|
||||
//! @return A reference to the object pointed to.
|
||||
static auto peek(const boost::intrusive_ptr<Class>& arg) -> const Class& {
|
||||
return *arg;
|
||||
}
|
||||
|
||||
//! Cast method argument to overrider argument.
|
||||
//!
|
||||
//! Cast a `boost::intrusive_ptr` to a `boost::intrusive_ptr` to a derived
|
||||
//! class, using a static cast if possible, and a dynamic cast otherwise.
|
||||
//!
|
||||
//! @tparam OverriderType The type required by the overrider (a `const
|
||||
//! boost::intrusive_ptr&`).
|
||||
//! @param obj The method's argument..
|
||||
//! @return A `boost::intrusive_ptr` _value_.
|
||||
template<class OverriderType>
|
||||
static decltype(auto) cast(const boost::intrusive_ptr<Class>& obj) {
|
||||
if constexpr (std::is_same_v<
|
||||
OverriderType, const boost::intrusive_ptr<Class>&>) {
|
||||
return obj;
|
||||
} else {
|
||||
using element_type =
|
||||
typename std::remove_reference_t<OverriderType>::element_type;
|
||||
|
||||
if constexpr (detail::requires_dynamic_cast<
|
||||
Class*, element_type*>) {
|
||||
// make it work with custom RTTI
|
||||
return std::remove_const_t<
|
||||
std::remove_reference_t<OverriderType>>(
|
||||
&Registry::rtti::template dynamic_cast_ref<element_type&>(
|
||||
*obj));
|
||||
} else {
|
||||
return boost::static_pointer_cast<element_type>(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//! Alias for a `virtual_ptr<boost::intrusive_ptr<T>>`.
|
||||
template<class Class, class Registry = BOOST_OPENMETHOD_DEFAULT_REGISTRY>
|
||||
using boost_intrusive_virtual_ptr =
|
||||
virtual_ptr<boost::intrusive_ptr<Class>, Registry>;
|
||||
|
||||
//! Create a new object and return a `boost_intrusive_virtual_ptr` to it.
|
||||
//!
|
||||
//! Create an object using `std::make_shared`, and return a @ref
|
||||
//! boost_intrusive_virtual_ptr pointing to it. Since the exact class of the
|
||||
//! object is known, the `virtual_ptr` is created using @ref final_virtual_ptr.
|
||||
//!
|
||||
//! `Class` is _not_ required to be a polymorphic class.
|
||||
//!
|
||||
//! @tparam Class The class of the object to create.
|
||||
//! @tparam Registry A @ref registry.
|
||||
//! @tparam T Types of the arguments to pass to the constructor of `Class`.
|
||||
//! @param args Arguments to pass to the constructor of `Class`.
|
||||
//! @return A `boost_intrusive_virtual_ptr<Class, Registry>` pointing to a newly
|
||||
//! created object of type `Class`.
|
||||
template<
|
||||
class Class, class Registry = BOOST_OPENMETHOD_DEFAULT_REGISTRY,
|
||||
typename... T>
|
||||
inline auto make_boost_intrusive_virtual(T&&... args) {
|
||||
return final_virtual_ptr<Registry>(intrusive_ptr<Class>(
|
||||
new std::remove_cv_t<Class>(std::forward<T>(args)...)));
|
||||
}
|
||||
|
||||
namespace aliases {
|
||||
using boost::openmethod::boost_intrusive_virtual_ptr;
|
||||
using boost::openmethod::make_boost_intrusive_virtual;
|
||||
} // namespace aliases
|
||||
|
||||
} // namespace boost::openmethod
|
||||
|
||||
#endif
|
||||
@@ -167,15 +167,20 @@ struct virtual_traits<const std::shared_ptr<Class>&, Registry> {
|
||||
//! @return A `std::shared_ptr` to the same object, cast to
|
||||
//! `Derived::element_type`.
|
||||
template<class Other>
|
||||
static auto cast(const std::shared_ptr<Class>& obj) {
|
||||
using namespace boost::openmethod::detail;
|
||||
|
||||
if constexpr (requires_dynamic_cast<Class*, Other>) {
|
||||
return std::dynamic_pointer_cast<
|
||||
typename shared_ptr_cast_traits<Other>::virtual_type>(obj);
|
||||
static decltype(auto) cast(const std::shared_ptr<Class>& obj) {
|
||||
if constexpr (std::is_same_v<Other, const std::shared_ptr<Class>&>) {
|
||||
// avoid unnecessary copy
|
||||
return obj;
|
||||
} else {
|
||||
return std::static_pointer_cast<
|
||||
typename shared_ptr_cast_traits<Other>::virtual_type>(obj);
|
||||
using namespace boost::openmethod::detail;
|
||||
|
||||
if constexpr (requires_dynamic_cast<Class*, Other>) {
|
||||
return std::dynamic_pointer_cast<
|
||||
typename shared_ptr_cast_traits<Other>::virtual_type>(obj);
|
||||
} else {
|
||||
return std::static_pointer_cast<
|
||||
typename shared_ptr_cast_traits<Other>::virtual_type>(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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< \
|
||||
@@ -79,7 +77,9 @@ struct va_args<ReturnType> {
|
||||
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...> \
|
||||
@@ -136,6 +136,6 @@ struct va_args<ReturnType> {
|
||||
-> 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
|
||||
|
||||
@@ -183,7 +183,7 @@ struct vptr_vector : vptr {
|
||||
} else {
|
||||
detail::vptr_vector_vptrs<Registry>.clear();
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
@@ -376,12 +377,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 +670,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 +712,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 +729,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 +937,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 +948,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);
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
169
test/test_dispatch_intrusive_ptr.cpp
Normal file
169
test/test_dispatch_intrusive_ptr.cpp
Normal file
@@ -0,0 +1,169 @@
|
||||
// Copyright (c) 2018-2025 Jean-Louis Leroy
|
||||
// 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)
|
||||
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <any>
|
||||
|
||||
#include <boost/openmethod.hpp>
|
||||
#include <boost/openmethod/interop/boost_intrusive_ptr.hpp>
|
||||
#include <boost/openmethod/initialize.hpp>
|
||||
#include <boost/smart_ptr/intrusive_ptr.hpp>
|
||||
#include <boost/smart_ptr/intrusive_ref_counter.hpp>
|
||||
|
||||
#define BOOST_TEST_MODULE openmethod
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
using namespace boost::openmethod;
|
||||
|
||||
#define MAKE_CLASSES() \
|
||||
struct Animal : boost::intrusive_ref_counter<Animal> { \
|
||||
explicit Animal(std::string str) { \
|
||||
name = std::move(str); \
|
||||
} \
|
||||
\
|
||||
Animal(const Animal&) = delete; \
|
||||
Animal(Animal&&) = default; \
|
||||
virtual ~Animal() = default; \
|
||||
\
|
||||
std::string name; \
|
||||
}; \
|
||||
\
|
||||
struct Dog : Animal { \
|
||||
using Animal::Animal; \
|
||||
}; \
|
||||
\
|
||||
struct Cat : virtual Animal { \
|
||||
using Animal::Animal; \
|
||||
}; \
|
||||
\
|
||||
BOOST_OPENMETHOD_CLASSES(Animal, Dog, Cat);
|
||||
|
||||
namespace BOOST_OPENMETHOD_GENSYM {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// pass virtual args by shared_ptr by value
|
||||
|
||||
MAKE_CLASSES();
|
||||
|
||||
BOOST_OPENMETHOD(
|
||||
name, (virtual_<boost::intrusive_ptr<const Animal>>), std::string);
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(
|
||||
name, (boost::intrusive_ptr<const Cat> cat), std::string) {
|
||||
return cat->name + " the cat";
|
||||
}
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(
|
||||
name, (boost::intrusive_ptr<const Dog> dog), std::string) {
|
||||
return dog->name + " the dog";
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(intrusive_ptr_by_value) {
|
||||
initialize();
|
||||
|
||||
auto spot = boost::intrusive_ptr<const Dog>(new Dog("Spot"));
|
||||
BOOST_TEST(name(spot) == "Spot the dog");
|
||||
|
||||
auto felix = boost::intrusive_ptr<const Cat>(new Cat("Felix"));
|
||||
BOOST_TEST(name(felix) == "Felix the cat");
|
||||
}
|
||||
} // namespace BOOST_OPENMETHOD_GENSYM
|
||||
|
||||
namespace BOOST_OPENMETHOD_GENSYM {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// pass virtual args by shared_ptr by const&
|
||||
|
||||
MAKE_CLASSES();
|
||||
|
||||
BOOST_OPENMETHOD(
|
||||
name, (virtual_<const boost::intrusive_ptr<const Animal>&>), std::string);
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(
|
||||
name, (const boost::intrusive_ptr<const Cat>& cat), std::string) {
|
||||
return cat->name + " the cat";
|
||||
}
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(
|
||||
name, (const boost::intrusive_ptr<const Dog>& dog), std::string) {
|
||||
return dog->name + " the dog";
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(intrusive_ptr_by_const_ref) {
|
||||
initialize();
|
||||
|
||||
auto spot = boost::intrusive_ptr<const Dog>(new Dog("Spot"));
|
||||
BOOST_TEST(name(spot) == "Spot the dog");
|
||||
|
||||
auto felix = boost::intrusive_ptr<const Cat>(new Cat("Felix"));
|
||||
BOOST_TEST(name(felix) == "Felix the cat");
|
||||
}
|
||||
} // namespace BOOST_OPENMETHOD_GENSYM
|
||||
|
||||
namespace BOOST_OPENMETHOD_GENSYM {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// virtual_ptr<intrusive_ptr> by value
|
||||
|
||||
MAKE_CLASSES();
|
||||
|
||||
BOOST_OPENMETHOD(
|
||||
name, (boost_intrusive_virtual_ptr<const Animal>), std::string);
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(
|
||||
name, (boost_intrusive_virtual_ptr<const Cat> cat), std::string) {
|
||||
return cat->name + " the cat";
|
||||
}
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(
|
||||
name, (boost_intrusive_virtual_ptr<const Dog> dog), std::string) {
|
||||
return dog->name + " the dog";
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(intrusive_virtual_ptr_by_value) {
|
||||
initialize();
|
||||
|
||||
auto spot = make_boost_intrusive_virtual<const Dog>("Spot");
|
||||
BOOST_TEST(name(spot) == "Spot the dog");
|
||||
|
||||
auto felix = make_boost_intrusive_virtual<const Cat>("Felix");
|
||||
BOOST_TEST(name(felix) == "Felix the cat");
|
||||
}
|
||||
} // namespace BOOST_OPENMETHOD_GENSYM
|
||||
|
||||
|
||||
namespace BOOST_OPENMETHOD_GENSYM {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// virtual_ptr<intrusive_ptr> by const&
|
||||
|
||||
MAKE_CLASSES();
|
||||
|
||||
BOOST_OPENMETHOD(
|
||||
name, (const boost_intrusive_virtual_ptr<const Animal>&), std::string);
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(
|
||||
name, (const boost_intrusive_virtual_ptr<const Cat>& cat), std::string) {
|
||||
return cat->name + " the cat";
|
||||
}
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(
|
||||
name, (const boost_intrusive_virtual_ptr<const Dog>& dog), std::string) {
|
||||
return dog->name + " the dog";
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(intrusive_virtual_ptr_by_const_ref) {
|
||||
initialize();
|
||||
|
||||
auto spot = make_boost_intrusive_virtual<const Dog>("Spot");
|
||||
BOOST_TEST(name(spot) == "Spot the dog");
|
||||
|
||||
auto felix = make_boost_intrusive_virtual<const Cat>("Felix");
|
||||
BOOST_TEST(name(felix) == "Felix the cat");
|
||||
}
|
||||
} // namespace BOOST_OPENMETHOD_GENSYM
|
||||
443
test/test_smart_virtual_ptr_value_semantics.cpp
Normal file
443
test/test_smart_virtual_ptr_value_semantics.cpp
Normal file
@@ -0,0 +1,443 @@
|
||||
// Copyright (c) 2018-2025 Jean-Louis Leroy
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// See accompanying file LICENSE_1_0.txt
|
||||
// or q at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/openmethod/interop/std_shared_ptr.hpp>
|
||||
#include <boost/openmethod/interop/boost_intrusive_ptr.hpp>
|
||||
|
||||
#define BOOST_TEST_MODULE openmethod
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <boost/utility/identity_type.hpp>
|
||||
|
||||
#include "test_virtual_ptr_value_semantics.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#ifdef BOOST_GCC
|
||||
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic ignored "-Wunused-local-typedefs"
|
||||
#endif
|
||||
|
||||
struct using_shared_ptr {
|
||||
template<class Class>
|
||||
using ptr = std::shared_ptr<Class>;
|
||||
|
||||
template<class Class>
|
||||
using virtual_ptr = shared_virtual_ptr<Class>;
|
||||
|
||||
template<class Class, class... Args>
|
||||
static decltype(auto) make(Args&&... args) {
|
||||
return std::make_shared<Class>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<class Class, class... Args>
|
||||
static decltype(auto) make_virtual(Args&&... args) {
|
||||
return make_shared_virtual<Class>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
static bool cast_moves() {
|
||||
initialize();
|
||||
|
||||
ptr<Animal> animal = make<Dog>();
|
||||
(void)std::static_pointer_cast<Dog>(animal);
|
||||
|
||||
return animal.get() == nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
struct using_boost_intrusive_ptr {
|
||||
template<class Class>
|
||||
using ptr = boost::intrusive_ptr<Class>;
|
||||
|
||||
template<class Class>
|
||||
using virtual_ptr = boost_intrusive_virtual_ptr<Class>;
|
||||
|
||||
template<class Class, class... Args>
|
||||
static auto make(Args&&... args) {
|
||||
return boost::intrusive_ptr<Class>(
|
||||
new Class(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template<class Class, class... Args>
|
||||
static auto make_virtual(Args&&... args) {
|
||||
return make_boost_intrusive_virtual<Class>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
static bool cast_moves() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
using smart_pointers =
|
||||
boost::mp11::mp_list<using_shared_ptr, using_boost_intrusive_ptr>;
|
||||
|
||||
#define USING_DECLARATIONS \
|
||||
using animal_ptr = typename smart::template ptr<Animal>; \
|
||||
using const_animal_ptr = typename smart::template ptr<const Animal>; \
|
||||
using animal_virtual_ptr = typename smart::template virtual_ptr<Animal>; \
|
||||
using const_animal_virtual_ptr = \
|
||||
typename smart::template virtual_ptr<const Animal>; \
|
||||
using dog_ptr = typename smart::template ptr<Dog>; \
|
||||
using const_dog_ptr = typename smart::template ptr<const Dog>; \
|
||||
using dog_virtual_ptr = typename smart::template virtual_ptr<Dog>; \
|
||||
using const_dog_virtual_ptr = \
|
||||
typename smart::template virtual_ptr<const Dog>; \
|
||||
using cat_ptr = typename smart::template ptr<Cat>; \
|
||||
using const_cat_ptr = typename smart::template ptr<const Cat>; \
|
||||
using cat_virtual_ptr = typename smart::template virtual_ptr<Cat>; \
|
||||
using const_cat_virtual_ptr = \
|
||||
typename smart::template virtual_ptr<const Cat>;
|
||||
|
||||
BOOST_AUTO_TEST_CASE_TEMPLATE(
|
||||
smart_pointer_value_semantics, smart, smart_pointers) {
|
||||
USING_DECLARATIONS;
|
||||
|
||||
static_assert(SameSmartPtr<animal_ptr, dog_ptr, default_registry>);
|
||||
static_assert(
|
||||
!SameSmartPtr<animal_ptr, std::unique_ptr<Dog>, default_registry>);
|
||||
static_assert(
|
||||
std::is_same_v<typename animal_virtual_ptr::element_type, Animal>);
|
||||
static_assert(std::is_same_v<
|
||||
decltype(std::declval<animal_virtual_ptr>().get()), Animal*>);
|
||||
static_assert(IsSmartPtr<animal_ptr, default_registry>);
|
||||
static_assert(IsSmartPtr<const_animal_ptr, default_registry>);
|
||||
static_assert(
|
||||
std::is_same_v<decltype(*std::declval<animal_virtual_ptr>()), Animal&>);
|
||||
|
||||
initialize();
|
||||
|
||||
// construction and assignment from a plain pointer or reference is not
|
||||
// allowed
|
||||
|
||||
static_assert(!construct_assign_ok<dog_virtual_ptr, Dog>);
|
||||
static_assert(!construct_assign_ok<dog_virtual_ptr, Dog&&>);
|
||||
static_assert(!construct_assign_ok<dog_virtual_ptr, const Dog&>);
|
||||
static_assert(!construct_assign_ok<dog_virtual_ptr, const Dog*>);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// construction and assignment from plain references and pointers
|
||||
|
||||
{
|
||||
dog_virtual_ptr p{nullptr};
|
||||
BOOST_TEST(p.get() == nullptr);
|
||||
BOOST_TEST(p.vptr() == nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
auto snoopy = smart::template make<Dog>();
|
||||
dog_virtual_ptr p(snoopy);
|
||||
BOOST_TEST(p.get() == snoopy.get());
|
||||
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Dog>);
|
||||
|
||||
p = *&p;
|
||||
BOOST_TEST(p.get() == snoopy.get());
|
||||
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Dog>);
|
||||
|
||||
auto hector = smart::template make<Dog>();
|
||||
p = hector;
|
||||
BOOST_TEST(p.get() == hector.get());
|
||||
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Dog>);
|
||||
}
|
||||
|
||||
{
|
||||
auto snoopy = smart::template make<Dog>();
|
||||
animal_virtual_ptr p(snoopy);
|
||||
BOOST_TEST(p.get() == snoopy.get());
|
||||
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Dog>);
|
||||
|
||||
auto felix = smart::template make<Cat>();
|
||||
p = felix;
|
||||
BOOST_TEST(p.get() == felix.get());
|
||||
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Cat>);
|
||||
}
|
||||
|
||||
{
|
||||
auto snoopy = smart::template make<const Dog>();
|
||||
const_dog_virtual_ptr p(snoopy);
|
||||
BOOST_TEST(p.get() == snoopy.get());
|
||||
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Dog>);
|
||||
|
||||
auto hector = smart::template make<const Dog>();
|
||||
p = hector;
|
||||
BOOST_TEST(p.get() == hector.get());
|
||||
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Dog>);
|
||||
}
|
||||
|
||||
{
|
||||
const auto snoopy = smart::template make<const Dog>();
|
||||
const_animal_virtual_ptr p(snoopy);
|
||||
BOOST_TEST(p.get() == snoopy.get());
|
||||
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Dog>);
|
||||
|
||||
auto felix = smart::template make<const Cat>();
|
||||
p = felix;
|
||||
BOOST_TEST(p.get() == felix.get());
|
||||
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Cat>);
|
||||
}
|
||||
|
||||
{
|
||||
auto snoopy = smart::template make<Dog>();
|
||||
dog_virtual_ptr p(snoopy);
|
||||
BOOST_TEST(p.get() == snoopy.get());
|
||||
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Dog>);
|
||||
|
||||
auto hector = smart::template make<Dog>();
|
||||
p = hector;
|
||||
BOOST_TEST(p.get() == hector.get());
|
||||
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Dog>);
|
||||
}
|
||||
|
||||
{
|
||||
auto snoopy = smart::template make<Dog>();
|
||||
animal_virtual_ptr p(snoopy);
|
||||
BOOST_TEST(p.get() == snoopy.get());
|
||||
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Dog>);
|
||||
|
||||
auto felix = smart::template make<Cat>();
|
||||
p = felix;
|
||||
BOOST_TEST(p.get() == felix.get());
|
||||
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Cat>);
|
||||
}
|
||||
|
||||
{
|
||||
auto snoopy = smart::template make<const Dog>();
|
||||
const_dog_virtual_ptr p(snoopy);
|
||||
BOOST_TEST(p.get() == snoopy.get());
|
||||
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Dog>);
|
||||
|
||||
auto hector = smart::template make<const Dog>();
|
||||
p = hector;
|
||||
BOOST_TEST(p.get() == hector.get());
|
||||
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Dog>);
|
||||
}
|
||||
|
||||
{
|
||||
auto snoopy = smart::template make<const Dog>();
|
||||
const_animal_virtual_ptr p(snoopy);
|
||||
BOOST_TEST(p.get() == snoopy.get());
|
||||
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Dog>);
|
||||
|
||||
auto felix = smart::template make<const Cat>();
|
||||
p = felix;
|
||||
BOOST_TEST(p.get() == felix.get());
|
||||
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Cat>);
|
||||
}
|
||||
|
||||
// dog_virtual_ptr p{Dog()};
|
||||
static_assert(!construct_assign_ok<dog_virtual_ptr, Dog&&>);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// construction and assignment from other shared_virtual_ptr
|
||||
|
||||
{
|
||||
// dog_virtual_ptr(const dog_virtual_ptr&)
|
||||
auto snoopy = smart::template make<Dog>();
|
||||
const dog_virtual_ptr p(snoopy);
|
||||
dog_virtual_ptr q(p);
|
||||
BOOST_TEST(q.get() == snoopy.get());
|
||||
BOOST_TEST(q.vptr() == default_registry::template static_vptr<Dog>);
|
||||
}
|
||||
|
||||
{
|
||||
// dog_virtual_ptr(dog_virtual_ptr&)
|
||||
auto snoopy = smart::template make<Dog>();
|
||||
dog_virtual_ptr p(snoopy);
|
||||
dog_virtual_ptr q(p);
|
||||
BOOST_TEST(q.get() == snoopy.get());
|
||||
BOOST_TEST(q.vptr() == default_registry::template static_vptr<Dog>);
|
||||
}
|
||||
|
||||
{
|
||||
// dog_virtual_ptr(dog_virtual_ptr&&)
|
||||
auto snoopy = smart::template make<Dog>();
|
||||
dog_virtual_ptr p(snoopy);
|
||||
dog_virtual_ptr q(std::move(p));
|
||||
BOOST_TEST(q.get() == snoopy.get());
|
||||
BOOST_TEST(q.vptr() == default_registry::template static_vptr<Dog>);
|
||||
BOOST_TEST(p.get() == nullptr);
|
||||
BOOST_TEST(p.vptr() == nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
// animal_virtual_ptr(const dog_virtual_ptr&)
|
||||
auto snoopy = smart::template make<Dog>();
|
||||
const dog_virtual_ptr p(snoopy);
|
||||
animal_virtual_ptr base(p);
|
||||
BOOST_TEST(base.get() == snoopy.get());
|
||||
BOOST_TEST(base.vptr() == default_registry::template static_vptr<Dog>);
|
||||
}
|
||||
|
||||
{
|
||||
// shared_virtual_ptr<const Dog>(const dog_virtual_ptr&)
|
||||
auto snoopy = smart::template make<Dog>();
|
||||
const dog_virtual_ptr p(snoopy);
|
||||
const_dog_virtual_ptr const_q(p);
|
||||
BOOST_TEST(const_q.get() == snoopy.get());
|
||||
BOOST_TEST(
|
||||
const_q.vptr() == default_registry::template static_vptr<Dog>);
|
||||
}
|
||||
|
||||
{
|
||||
// shared_virtual_ptr<const Animal>(const dog_virtual_ptr&)
|
||||
auto snoopy = smart::template make<Dog>();
|
||||
const dog_virtual_ptr p(snoopy);
|
||||
const_animal_virtual_ptr const_base_q(p);
|
||||
BOOST_TEST(const_base_q.get() == snoopy.get());
|
||||
BOOST_TEST(
|
||||
const_base_q.vptr() == default_registry::template static_vptr<Dog>);
|
||||
}
|
||||
|
||||
{
|
||||
// dog_virtual_ptr()
|
||||
dog_virtual_ptr p{nullptr};
|
||||
BOOST_TEST(p.get() == nullptr);
|
||||
BOOST_TEST(p.vptr() == nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
dog_virtual_ptr p{dog_ptr()};
|
||||
BOOST_TEST(p.get() == nullptr);
|
||||
BOOST_TEST(p.vptr() == nullptr);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// assignment
|
||||
|
||||
{
|
||||
dog_virtual_ptr p;
|
||||
auto snoopy = smart::template make<Dog>();
|
||||
p = snoopy;
|
||||
BOOST_TEST(p.get() == snoopy.get());
|
||||
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Dog>);
|
||||
}
|
||||
|
||||
{
|
||||
dog_virtual_ptr p;
|
||||
auto snoopy = smart::template make<Dog>();
|
||||
p = snoopy;
|
||||
BOOST_TEST(p.get() == snoopy.get());
|
||||
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Dog>);
|
||||
}
|
||||
|
||||
{
|
||||
auto p = smart::template make_virtual<Dog>();
|
||||
p = nullptr;
|
||||
BOOST_TEST(p.get() == nullptr);
|
||||
BOOST_TEST(p.vptr() == nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
auto p = smart::template make_virtual<Dog>();
|
||||
p = dog_ptr();
|
||||
BOOST_TEST(p.get() == nullptr);
|
||||
BOOST_TEST(p.vptr() == nullptr);
|
||||
}
|
||||
|
||||
static_assert(!construct_assign_ok<dog_virtual_ptr, const Dog&>);
|
||||
static_assert(!construct_assign_ok<dog_virtual_ptr, const Dog*>);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE_TEMPLATE(cast_smart_pointer_value, smart, smart_pointers) {
|
||||
USING_DECLARATIONS;
|
||||
|
||||
initialize();
|
||||
|
||||
animal_ptr animal = smart::template make<Dog>();
|
||||
dog_ptr dog =
|
||||
virtual_traits<animal_ptr, default_registry>::template cast<dog_ptr>(
|
||||
animal);
|
||||
BOOST_TEST(dog.get() == animal.get());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE_TEMPLATE(
|
||||
cast_smart_ptr_lvalue_reference, smart, smart_pointers) {
|
||||
USING_DECLARATIONS;
|
||||
|
||||
initialize();
|
||||
|
||||
animal_ptr animal = smart::template make<Dog>();
|
||||
dog_ptr dog =
|
||||
virtual_traits<const animal_ptr&, default_registry>::template cast<
|
||||
const dog_ptr&>(animal);
|
||||
BOOST_TEST(dog.get() == animal.get());
|
||||
|
||||
dog_ptr dog2 = virtual_traits<
|
||||
const dog_ptr&, default_registry>::template cast<const dog_ptr&>(dog);
|
||||
BOOST_TEST(dog2.get() == dog.get());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE_TEMPLATE(
|
||||
cast_smart_ptr_xvalue_reference, smart, smart_pointers) {
|
||||
USING_DECLARATIONS;
|
||||
|
||||
initialize();
|
||||
|
||||
animal_ptr animal = smart::template make<Dog>();
|
||||
auto p = animal.get();
|
||||
auto dog =
|
||||
virtual_traits<animal_ptr, default_registry>::template cast<dog_ptr>(
|
||||
std::move(animal));
|
||||
BOOST_TEST(dog.get() == p);
|
||||
|
||||
if (smart::cast_moves()) {
|
||||
BOOST_TEST(animal.get() == nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE_TEMPLATE(
|
||||
cast_shared_virtual_ptr_value, smart, smart_pointers) {
|
||||
USING_DECLARATIONS;
|
||||
|
||||
initialize();
|
||||
|
||||
animal_virtual_ptr base = smart::template make<Dog>();
|
||||
auto derived = virtual_traits<
|
||||
animal_virtual_ptr, default_registry>::template cast<dog_ptr>(base);
|
||||
BOOST_TEST(derived.get() == base.get());
|
||||
BOOST_TEST(base.vptr() == default_registry::static_vptr<Dog>);
|
||||
BOOST_TEST(derived.vptr() == default_registry::static_vptr<Dog>);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE_TEMPLATE(
|
||||
cast_shared_virtual_ptr_lvalue_reference, smart, smart_pointers) {
|
||||
USING_DECLARATIONS;
|
||||
|
||||
initialize();
|
||||
|
||||
animal_virtual_ptr base = smart::template make<Dog>();
|
||||
auto derived = virtual_traits<const animal_virtual_ptr&, default_registry>::
|
||||
template cast<const dog_virtual_ptr&>(base);
|
||||
BOOST_TEST(derived.get() == base.get());
|
||||
BOOST_TEST(base.vptr() == default_registry::static_vptr<Dog>);
|
||||
BOOST_TEST(derived.vptr() == default_registry::static_vptr<Dog>);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE_TEMPLATE(
|
||||
cast_shared_virtual_ptr_xvalue_reference, smart, smart_pointers) {
|
||||
USING_DECLARATIONS;
|
||||
|
||||
initialize();
|
||||
|
||||
animal_virtual_ptr base = smart::template make<Dog>();
|
||||
auto p = base.get();
|
||||
auto derived =
|
||||
virtual_traits<animal_virtual_ptr, default_registry>::template cast<
|
||||
dog_virtual_ptr>(std::move(base));
|
||||
BOOST_TEST(derived.get() == p);
|
||||
BOOST_TEST(derived.vptr() == default_registry::static_vptr<Dog>);
|
||||
|
||||
if (smart::cast_moves()) {
|
||||
BOOST_TEST(base.get() == nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
template struct check_illegal_smart_ops<
|
||||
std::shared_ptr, std::unique_ptr, direct_vector>;
|
||||
|
||||
template struct check_illegal_smart_ops<
|
||||
boost::intrusive_ptr, std::unique_ptr, direct_vector>;
|
||||
@@ -116,6 +116,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(
|
||||
unique_virtual_ptr<Dog, Registry> p(std::make_unique<Dog>());
|
||||
auto dog = p.get();
|
||||
unique_virtual_ptr<Dog, Registry> q(std::move(p));
|
||||
// coverity[use_after_move]
|
||||
BOOST_TEST(q.get() == dog);
|
||||
BOOST_TEST(q.vptr() == Registry::template static_vptr<Dog>);
|
||||
BOOST_TEST(p.get() == nullptr);
|
||||
@@ -127,6 +128,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(
|
||||
unique_virtual_ptr<Dog, Registry> p(std::make_unique<Dog>());
|
||||
auto dog = p.get();
|
||||
unique_virtual_ptr<Animal, Registry> q(std::move(p));
|
||||
// coverity[use_after_move]
|
||||
BOOST_TEST(q.get() == dog);
|
||||
BOOST_TEST(q.vptr() == Registry::template static_vptr<Dog>);
|
||||
BOOST_TEST(p.get() == nullptr);
|
||||
|
||||
@@ -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) {
|
||||
{
|
||||
|
||||
@@ -168,6 +168,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(
|
||||
Dog snoopy;
|
||||
virtual_ptr<Dog, Registry> p(snoopy);
|
||||
virtual_ptr<Dog, Registry> q(std::move(p));
|
||||
// coverity[use_after_move]
|
||||
BOOST_TEST(q.get() == &snoopy);
|
||||
BOOST_TEST(q.vptr() == Registry::template static_vptr<Dog>);
|
||||
BOOST_TEST(p.get() == &snoopy);
|
||||
|
||||
@@ -6,10 +6,16 @@
|
||||
#ifndef TEST_VIRTUAL_PTR_VALUE_SEMANTICS_HPP
|
||||
#define TEST_VIRTUAL_PTR_VALUE_SEMANTICS_HPP
|
||||
|
||||
#include <type_traits>
|
||||
#include <boost/mp11.hpp>
|
||||
#include <boost/openmethod.hpp>
|
||||
#include <boost/openmethod/policies/vptr_map.hpp>
|
||||
#include <boost/openmethod/initialize.hpp>
|
||||
#include <boost/openmethod/policies/vptr_map.hpp>
|
||||
#include <boost/openmethod/interop/std_shared_ptr.hpp>
|
||||
#include <boost/openmethod/interop/boost_intrusive_ptr.hpp>
|
||||
#include <boost/openmethod/interop/std_unique_ptr.hpp>
|
||||
#include <boost/smart_ptr/intrusive_ptr.hpp>
|
||||
#include <boost/smart_ptr/intrusive_ref_counter.hpp>
|
||||
|
||||
#include "test_util.hpp"
|
||||
|
||||
@@ -19,7 +25,7 @@ using namespace boost::openmethod;
|
||||
using namespace policies;
|
||||
using namespace detail;
|
||||
|
||||
struct Animal {
|
||||
struct Animal : boost::intrusive_ref_counter<Animal> {
|
||||
virtual ~Animal() {
|
||||
}
|
||||
|
||||
@@ -31,6 +37,12 @@ struct Cat : virtual Animal {};
|
||||
|
||||
struct Dog : Animal {};
|
||||
|
||||
BOOST_OPENMETHOD_CLASSES(Animal, Cat, Dog);
|
||||
|
||||
struct id;
|
||||
// without following line, no methods, no v-tables
|
||||
auto instantiate_a_method = &method<id, auto(virtual_ptr<Animal>)->void>::fn;
|
||||
|
||||
template<class Left, class Right>
|
||||
constexpr bool construct_assign_ok =
|
||||
std::is_constructible_v<Left, Right> && std::is_assignable_v<Left, Right>;
|
||||
|
||||
Reference in New Issue
Block a user