diff --git a/.clang-format b/.clang-format
index b26254bd..9e499faf 100644
--- a/.clang-format
+++ b/.clang-format
@@ -44,10 +44,10 @@ BraceWrapping:
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
-BreakInheritanceList: BeforeColon
+BreakInheritanceList: AfterColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
-BreakConstructorInitializers: BeforeColon
+BreakConstructorInitializers: AfterColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 80
@@ -102,7 +102,7 @@ PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
-PenaltyReturnTypeOnItsOwnLine: 60
+PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
ReflowComments: false
SortIncludes: false
@@ -133,4 +133,6 @@ StatementMacros:
TabWidth: 8
UseCRLF: false
UseTab: Never
+TemplateNames:
+ - register_classes
...
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 874b7827..60987562 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -54,6 +54,48 @@ jobs:
COVERITY_SCAN_NOTIFICATION_EMAIL: ${{ secrets.COVERITY_SCAN_NOTIFICATION_EMAIL }}
COVERITY_SCAN_TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
+ reflection:
+ name: C++26 reflection
+ runs-on: ubuntu-24.04
+ steps:
+ - name: Install GCC 16
+ run: |
+ sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
+ sudo apt-get update
+ sudo apt-get install -y g++-16 cmake ninja-build
+
+ - name: Clone Boost.OpenMethod
+ uses: actions/checkout@v4
+
+ - name: Clone Boost
+ uses: alandefreitas/cpp-actions/boost-clone@v1.8.8
+ with:
+ # boost-clone excludes `test` and `tests` from the scan
+ # (modules-exclude-paths defaults to them), so it never sees the
+ # includes in our own test/ and would clone neither Boost.Test nor
+ # Boost.DLL - CMake then fails to generate on a missing
+ # Boost::unit_test_framework. `modules` is unioned with the scan,
+ # and their own dependencies are resolved afterwards.
+ modules: test dll
+ branch: ${{ (github.ref_name == 'master' && github.ref_name) || 'develop' }}
+ boost-dir: ../boost-source
+ scan-modules-dir: .
+ scan-modules-ignore: openmethod
+
+ # The suite is the reflection test: BOOST_OPENMETHOD_TEST_CLASSES expands
+ # to nothing here, so every class has to be found by use_classes_in.
+ - name: Build and test
+ run: |
+ cmake -S . -B ../build -G Ninja \
+ -DCMAKE_BUILD_TYPE=Debug \
+ -DCMAKE_CXX_COMPILER=g++-16 \
+ -DBOOST_OPENMETHOD_ENABLE_REFLECTION=ON \
+ -DBOOST_OPENMETHOD_BUILD_TESTS=ON \
+ -DBOOST_OPENMETHOD_WARNINGS_AS_ERRORS=ON \
+ -DBOOST_SRC_DIR="$(cd .. && pwd)/boost-source"
+ cmake --build ../build --target tests -j $(nproc)
+ ctest --test-dir ../build -j $(nproc) --output-on-failure
+
antora:
name: Antora docs
strategy:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5224a251..9f119dfd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -59,6 +59,81 @@ option(
BOOST_OPENMETHOD_WARNINGS_AS_ERRORS
"Treat warnings as errors"
OFF)
+option(
+ BOOST_OPENMETHOD_ENABLE_REFLECTION
+ "Build the tests and examples with C++26 reflection enabled"
+ OFF)
+
+# C++26 reflection (P2996). The library detects it on its own, from
+# __cpp_impl_reflection; this only arranges for the tests to be built in a mode
+# where the compiler provides it, which needs both C++26 and, on GCC, an opt-in
+# flag. It is applied per target rather than through CMAKE_CXX_FLAGS, because
+# CMake probes the compiler before CMAKE_CXX_STANDARD takes effect and GCC
+# rejects -freflection under any other standard.
+set(BOOST_OPENMETHOD_REFLECTION_OPTIONS "")
+
+if (BOOST_OPENMETHOD_ENABLE_REFLECTION)
+ include(CheckCXXSourceCompiles)
+
+ set(BOOST_OPENMETHOD_REFLECTION_TEST_SOURCE [[
+ #include
+ struct Base {};
+ struct Derived : Base {};
+ consteval auto count() -> int {
+ return static_cast(
+ std::meta::bases_of(
+ ^^Derived, std::meta::access_context::unchecked()).size());
+ }
+ static_assert(count() == 1);
+ int main() {}
+ ]])
+
+ set(CMAKE_REQUIRED_QUIET ON)
+
+ foreach(candidate "-std=c++26" "-std=c++26;-freflection")
+ string(REPLACE ";" " " candidate_flags "${candidate}")
+ set(CMAKE_REQUIRED_FLAGS "${candidate_flags}")
+ unset(BOOST_OPENMETHOD_HAS_REFLECTION CACHE)
+ check_cxx_source_compiles(
+ "${BOOST_OPENMETHOD_REFLECTION_TEST_SOURCE}"
+ BOOST_OPENMETHOD_HAS_REFLECTION)
+
+ if (BOOST_OPENMETHOD_HAS_REFLECTION)
+ set(BOOST_OPENMETHOD_REFLECTION_OPTIONS ${candidate})
+ break()
+ endif()
+ endforeach()
+
+ unset(CMAKE_REQUIRED_FLAGS)
+ unset(CMAKE_REQUIRED_QUIET)
+
+ if (NOT BOOST_OPENMETHOD_HAS_REFLECTION)
+ message(
+ FATAL_ERROR
+ "BOOST_OPENMETHOD_ENABLE_REFLECTION is ON but ${CMAKE_CXX_COMPILER_ID} "
+ "${CMAKE_CXX_COMPILER_VERSION} does not support C++26 reflection")
+ endif()
+
+ message(
+ STATUS
+ "Boost.OpenMethod: C++26 reflection enabled"
+ " [${BOOST_OPENMETHOD_REFLECTION_OPTIONS}]")
+endif()
+
+# Build `target` with C++26 reflection, if BOOST_OPENMETHOD_ENABLE_REFLECTION is
+# ON. Does nothing otherwise, so callers need no condition of their own.
+function(boost_openmethod_enable_reflection target)
+ if (NOT BOOST_OPENMETHOD_ENABLE_REFLECTION)
+ return()
+ endif()
+
+ # The standard flag is passed here rather than through CXX_STANDARD: CMake
+ # learned the value 26 only in 3.30, and this project supports older ones.
+ # target_compile_options come after the flag CMake derives from the
+ # library's cxx_std_17 requirement, and the last -std wins.
+ target_compile_options(
+ ${target} PRIVATE ${BOOST_OPENMETHOD_REFLECTION_OPTIONS})
+endfunction()
if (BOOST_OPENMETHOD_BUILD_EXAMPLES AND NOT BOOST_OPENMETHOD_BUILD_TESTS)
message(
diff --git a/doc/modules/ROOT/examples/CMakeLists.txt b/doc/modules/ROOT/examples/CMakeLists.txt
index f922ab9e..2b0555f2 100644
--- a/doc/modules/ROOT/examples/CMakeLists.txt
+++ b/doc/modules/ROOT/examples/CMakeLists.txt
@@ -21,6 +21,7 @@ foreach (cpp ${cpp_files})
get_filename_component(stem ${cpp} NAME_WE)
set(test_target "boost_openmethod-${stem}")
add_executable(${test_target} ${cpp})
+ boost_openmethod_enable_reflection(${test_target})
target_link_libraries(${test_target} PRIVATE Boost::openmethod Boost::unit_test_framework)
add_test(NAME ${test_target} COMMAND ${test_target})
add_dependencies(tests ${test_target})
@@ -43,6 +44,7 @@ function(boost_openmethod_add_step_by_step dir)
file(GLOB cpp_files "${subdir}/*.cpp")
set(target "boost_openmethod-${dir}_${subex}")
add_executable(${target} ${cpp_files})
+ boost_openmethod_enable_reflection(${target})
target_link_libraries(${target} PRIVATE Boost::openmethod)
set(output_dir openmethod/${dir}/${subex})
set_target_properties(${target} PROPERTIES
diff --git a/doc/modules/ROOT/examples/accept_no_visitors.cpp b/doc/modules/ROOT/examples/accept_no_visitors.cpp
index 4bcc656b..b63875eb 100644
--- a/doc/modules/ROOT/examples/accept_no_visitors.cpp
+++ b/doc/modules/ROOT/examples/accept_no_visitors.cpp
@@ -24,8 +24,8 @@ struct Node {
struct Plus : Node {
Plus(
shared_virtual_ptr left,
- shared_virtual_ptr right)
- : left(std::move(left)), right(std::move(right)) {
+ shared_virtual_ptr right) :
+ left(std::move(left)), right(std::move(right)) {
}
shared_virtual_ptr left, right;
@@ -34,8 +34,8 @@ struct Plus : Node {
struct Times : Node {
Times(
shared_virtual_ptr left,
- shared_virtual_ptr right)
- : left(std::move(left)), right(std::move(right)) {
+ shared_virtual_ptr right) :
+ left(std::move(left)), right(std::move(right)) {
}
shared_virtual_ptr left, right;
@@ -82,7 +82,8 @@ BOOST_OPENMETHOD_OVERRIDE(as_forth, (virtual_ptr node), string) {
return as_forth(node->left) + " " + as_forth(node->right) + " *";
}
-BOOST_OPENMETHOD_OVERRIDE(as_forth, (virtual_ptr node), string) {
+BOOST_OPENMETHOD_OVERRIDE(
+ as_forth, (virtual_ptr node), string) {
return std::to_string(node->value);
}
@@ -111,7 +112,8 @@ auto main() -> int {
shared_virtual_ptr node = make_shared_virtual(
make_shared_virtual(2),
make_shared_virtual(
- make_shared_virtual(3), make_shared_virtual(4)));
+ make_shared_virtual(3),
+ make_shared_virtual(4)));
cout << as_forth(node) << " = " << as_lisp(node) << " = " << value(node)
<< "\n";
diff --git a/doc/modules/ROOT/examples/inplace_vptr.cpp b/doc/modules/ROOT/examples/inplace_vptr.cpp
index ef07f99f..d23979e6 100644
--- a/doc/modules/ROOT/examples/inplace_vptr.cpp
+++ b/doc/modules/ROOT/examples/inplace_vptr.cpp
@@ -18,8 +18,7 @@ struct Cat : Animal, inplace_vptr_derived {};
struct Dog : Animal, inplace_vptr_derived {};
-BOOST_OPENMETHOD(
- poke, (virtual_ animal, std::ostream& os), void);
+BOOST_OPENMETHOD(poke, (virtual_ animal, std::ostream& os), void);
BOOST_OPENMETHOD_OVERRIDE(poke, (Cat&, std::ostream& os), void) {
os << "hiss\n";
diff --git a/doc/modules/ROOT/examples/matrix.cpp b/doc/modules/ROOT/examples/matrix.cpp
index dbf8d6c9..c6f65664 100644
--- a/doc/modules/ROOT/examples/matrix.cpp
+++ b/doc/modules/ROOT/examples/matrix.cpp
@@ -22,8 +22,8 @@ struct abstract {
int ref_count = 0;
};
-struct registry
- : boost::openmethod::registry {};
+struct registry :
+ boost::openmethod::registry {};
template
using matrix_ptr = boost::openmethod::virtual_ptr;
diff --git a/doc/modules/ROOT/examples/matrix_readme.cpp b/doc/modules/ROOT/examples/matrix_readme.cpp
index 4cf4a74f..790db429 100644
--- a/doc/modules/ROOT/examples/matrix_readme.cpp
+++ b/doc/modules/ROOT/examples/matrix_readme.cpp
@@ -23,15 +23,18 @@ BOOST_OPENMETHOD_CLASSES(Matrix, SquareMatrix, SymmetricMatrix, DiagonalMatrix);
BOOST_OPENMETHOD(to_json, (virtual_ptr, std::ostream& os), void);
-BOOST_OPENMETHOD_OVERRIDE(to_json, (virtual_ptr, std::ostream& os), void) {
+BOOST_OPENMETHOD_OVERRIDE(
+ to_json, (virtual_ptr, std::ostream& os), void) {
os << "all the elements\n";
}
-BOOST_OPENMETHOD_OVERRIDE(to_json, (virtual_ptr, std::ostream& os), void) {
+BOOST_OPENMETHOD_OVERRIDE(
+ to_json, (virtual_ptr, std::ostream& os), void) {
os << "elements above and including the diagonal\n";
}
-BOOST_OPENMETHOD_OVERRIDE(to_json, (virtual_ptr, std::ostream& os), void) {
+BOOST_OPENMETHOD_OVERRIDE(
+ to_json, (virtual_ptr, std::ostream& os), void) {
os << "just the diagonal\n";
}
diff --git a/doc/modules/ROOT/examples/rolex/1/main.cpp b/doc/modules/ROOT/examples/rolex/1/main.cpp
index 55010bc6..576991cc 100644
--- a/doc/modules/ROOT/examples/rolex/1/main.cpp
+++ b/doc/modules/ROOT/examples/rolex/1/main.cpp
@@ -15,9 +15,10 @@ int main() {
boost::openmethod::initialize();
Employee bill;
- Salesman bob; bob.sales = 100'000.0;
+ Salesman bob;
+ bob.sales = 100'000.0;
std::cout << "pay bill: $" << pay(bill) << "\n"; // pay bill: $5000
- std::cout << "pay bob: $" << pay(bob) << "\n"; // pay bob: $10000
+ std::cout << "pay bob: $" << pay(bob) << "\n"; // pay bob: $10000
}
// end::content[]
diff --git a/doc/modules/ROOT/examples/rolex/1/roles.hpp b/doc/modules/ROOT/examples/rolex/1/roles.hpp
index ca280b66..4a75702f 100644
--- a/doc/modules/ROOT/examples/rolex/1/roles.hpp
+++ b/doc/modules/ROOT/examples/rolex/1/roles.hpp
@@ -11,7 +11,9 @@
#include
-struct Employee { virtual ~Employee() = default; };
+struct Employee {
+ virtual ~Employee() = default;
+};
struct Salesman : Employee {
double sales = 0.0;
diff --git a/doc/modules/ROOT/examples/rolex/2/main.cpp b/doc/modules/ROOT/examples/rolex/2/main.cpp
index 55010bc6..576991cc 100644
--- a/doc/modules/ROOT/examples/rolex/2/main.cpp
+++ b/doc/modules/ROOT/examples/rolex/2/main.cpp
@@ -15,9 +15,10 @@ int main() {
boost::openmethod::initialize();
Employee bill;
- Salesman bob; bob.sales = 100'000.0;
+ Salesman bob;
+ bob.sales = 100'000.0;
std::cout << "pay bill: $" << pay(bill) << "\n"; // pay bill: $5000
- std::cout << "pay bob: $" << pay(bob) << "\n"; // pay bob: $10000
+ std::cout << "pay bob: $" << pay(bob) << "\n"; // pay bob: $10000
}
// end::content[]
diff --git a/doc/modules/ROOT/examples/rolex/2/roles.hpp b/doc/modules/ROOT/examples/rolex/2/roles.hpp
index 02e8b06f..74d9ccef 100644
--- a/doc/modules/ROOT/examples/rolex/2/roles.hpp
+++ b/doc/modules/ROOT/examples/rolex/2/roles.hpp
@@ -11,7 +11,9 @@
#include
-struct Employee { virtual ~Employee() = default; };
+struct Employee {
+ virtual ~Employee() = default;
+};
struct Salesman : Employee {
double sales = 0.0;
diff --git a/doc/modules/ROOT/examples/rolex/3/main.cpp b/doc/modules/ROOT/examples/rolex/3/main.cpp
index 55010bc6..576991cc 100644
--- a/doc/modules/ROOT/examples/rolex/3/main.cpp
+++ b/doc/modules/ROOT/examples/rolex/3/main.cpp
@@ -15,9 +15,10 @@ int main() {
boost::openmethod::initialize();
Employee bill;
- Salesman bob; bob.sales = 100'000.0;
+ Salesman bob;
+ bob.sales = 100'000.0;
std::cout << "pay bill: $" << pay(bill) << "\n"; // pay bill: $5000
- std::cout << "pay bob: $" << pay(bob) << "\n"; // pay bob: $10000
+ std::cout << "pay bob: $" << pay(bob) << "\n"; // pay bob: $10000
}
// end::content[]
diff --git a/doc/modules/ROOT/examples/rolex/3/roles.hpp b/doc/modules/ROOT/examples/rolex/3/roles.hpp
index ae92c34d..32313969 100644
--- a/doc/modules/ROOT/examples/rolex/3/roles.hpp
+++ b/doc/modules/ROOT/examples/rolex/3/roles.hpp
@@ -11,7 +11,9 @@
#include
-struct Employee { virtual ~Employee() = default; };
+struct Employee {
+ virtual ~Employee() = default;
+};
struct Salesman : Employee {
double sales = 0.0;
diff --git a/doc/modules/ROOT/examples/rolex/4/main.cpp b/doc/modules/ROOT/examples/rolex/4/main.cpp
index 5dea2ba0..1818021f 100644
--- a/doc/modules/ROOT/examples/rolex/4/main.cpp
+++ b/doc/modules/ROOT/examples/rolex/4/main.cpp
@@ -15,9 +15,10 @@ int main() {
boost::openmethod::initialize();
employees::Employee bill;
- sales::Salesman bob; bob.sales = 100'000.0;
+ sales::Salesman bob;
+ bob.sales = 100'000.0;
std::cout << "pay bill: $" << pay(bill) << "\n"; // pay bill: $5000
- std::cout << "pay bob: $" << pay(bob) << "\n"; // pay bob: $10000
+ std::cout << "pay bob: $" << pay(bob) << "\n"; // pay bob: $10000
}
// end::content[]
diff --git a/doc/modules/ROOT/examples/rolex/4/roles.hpp b/doc/modules/ROOT/examples/rolex/4/roles.hpp
index 500efeac..de41157a 100644
--- a/doc/modules/ROOT/examples/rolex/4/roles.hpp
+++ b/doc/modules/ROOT/examples/rolex/4/roles.hpp
@@ -24,7 +24,7 @@ BOOST_OPENMETHOD_INLINE_OVERRIDE(
return 5000.0;
}
-}
+} // namespace employees
namespace sales {
diff --git a/doc/modules/ROOT/examples/rolex/4/salesman.cpp b/doc/modules/ROOT/examples/rolex/4/salesman.cpp
index 74c03ace..5234441f 100644
--- a/doc/modules/ROOT/examples/rolex/4/salesman.cpp
+++ b/doc/modules/ROOT/examples/rolex/4/salesman.cpp
@@ -12,7 +12,8 @@ namespace sales {
BOOST_OPENMETHOD_OVERRIDE(
pay, (boost::openmethod::virtual_ptr emp), double) {
return employees::BOOST_OPENMETHOD_OVERRIDER(
- pay, (boost::openmethod::virtual_ptr emp),
+ pay,
+ (boost::openmethod::virtual_ptr emp),
double)::fn(emp) +
emp->sales * 0.05; // base + commission
}
diff --git a/doc/modules/ROOT/examples/rolex/5/main.cpp b/doc/modules/ROOT/examples/rolex/5/main.cpp
index 5adfe75f..c857352b 100644
--- a/doc/modules/ROOT/examples/rolex/5/main.cpp
+++ b/doc/modules/ROOT/examples/rolex/5/main.cpp
@@ -40,7 +40,8 @@ class Payroll {
}
friend BOOST_OPENMETHOD_OVERRIDER(
- pay, (Payroll & payroll, boost::openmethod::virtual_ptr),
+ pay,
+ (Payroll & payroll, boost::openmethod::virtual_ptr),
double);
friend BOOST_OPENMETHOD_OVERRIDER(
pay,
@@ -83,8 +84,8 @@ int main() {
Salesman bob;
bob.sales = 100'000.0;
- std::cout << "pay bill: $" << pay(payroll, bill) << "\n"; // $5000
- std::cout << "pay bob: $" << pay(payroll, bob) << "\n"; // 10000
+ std::cout << "pay bill: $" << pay(payroll, bill) << "\n"; // $5000
+ std::cout << "pay bob: $" << pay(payroll, bob) << "\n"; // 10000
std::cout << "remaining balance: $" << payroll.balance() << "\n"; // $985000
}
// end::main[]
diff --git a/doc/modules/ROOT/examples/throw_error_handler.cpp b/doc/modules/ROOT/examples/throw_error_handler.cpp
index f1c520bd..2b94fa94 100644
--- a/doc/modules/ROOT/examples/throw_error_handler.cpp
+++ b/doc/modules/ROOT/examples/throw_error_handler.cpp
@@ -33,8 +33,8 @@ struct throw_if_not_implemented : bom::policies::error_handler {
};
};
-struct custom_registry : bom::default_registry::with {
-};
+struct custom_registry :
+ bom::default_registry::with {};
using boost::openmethod::virtual_ptr;
diff --git a/doc/modules/ROOT/examples/virtual_ptr_alt/1/virtual_ptr_alt.cpp b/doc/modules/ROOT/examples/virtual_ptr_alt/1/virtual_ptr_alt.cpp
index d8318db3..706cbad2 100644
--- a/doc/modules/ROOT/examples/virtual_ptr_alt/1/virtual_ptr_alt.cpp
+++ b/doc/modules/ROOT/examples/virtual_ptr_alt/1/virtual_ptr_alt.cpp
@@ -11,21 +11,32 @@ struct Node {
};
struct Variable : Node {
- Variable(int value) : v(value) {}
- int value() const override { return v; }
+ Variable(int value) : v(value) {
+ }
+ int value() const override {
+ return v;
+ }
int v;
};
struct Plus : Node {
- Plus(const Node& left, const Node& right) : left(left), right(right) {}
- int value() const override { return left.value() + right.value(); }
- const Node& left; const Node& right;
+ Plus(const Node& left, const Node& right) : left(left), right(right) {
+ }
+ int value() const override {
+ return left.value() + right.value();
+ }
+ const Node& left;
+ const Node& right;
};
struct Times : Node {
- Times(const Node& left, const Node& right) : left(left), right(right) {}
- int value() const override { return left.value() * right.value(); }
- const Node& left; const Node& right;
+ Times(const Node& left, const Node& right) : left(left), right(right) {
+ }
+ int value() const override {
+ return left.value() * right.value();
+ }
+ const Node& left;
+ const Node& right;
};
#include
@@ -40,8 +51,7 @@ BOOST_OPENMETHOD_OVERRIDE(
os << var.v;
}
-BOOST_OPENMETHOD_OVERRIDE(
- postfix, (const Plus& plus, std::ostream& os), void) {
+BOOST_OPENMETHOD_OVERRIDE(postfix, (const Plus& plus, std::ostream& os), void) {
postfix(plus.left, os);
os << ' ';
postfix(plus.right, os);
diff --git a/doc/modules/ROOT/examples/virtual_ptr_alt/3/virtual_ptr_alt.cpp b/doc/modules/ROOT/examples/virtual_ptr_alt/3/virtual_ptr_alt.cpp
index c0039b82..f6619f34 100644
--- a/doc/modules/ROOT/examples/virtual_ptr_alt/3/virtual_ptr_alt.cpp
+++ b/doc/modules/ROOT/examples/virtual_ptr_alt/3/virtual_ptr_alt.cpp
@@ -8,24 +8,28 @@
#include
// tag::content[]
-struct Node : boost::openmethod::inplace_vptr_base {
-};
+struct Node : boost::openmethod::inplace_vptr_base {};
-struct Variable : Node, boost::openmethod::inplace_vptr_derived {
- Variable(int value) : v(value) {}
+struct Variable :
+ Node,
+ boost::openmethod::inplace_vptr_derived {
+ Variable(int value) : v(value) {
+ }
int v;
};
struct Plus : Node, boost::openmethod::inplace_vptr_derived {
- Plus(const Node& left, const Node& right) : left(left), right(right) {}
+ Plus(const Node& left, const Node& right) : left(left), right(right) {
+ }
const Node& left;
const Node& right;
};
struct Times : Node, boost::openmethod::inplace_vptr_derived {
- Times(const Node& left, const Node& right) : left(left), right(right) {}
+ Times(const Node& left, const Node& right) : left(left), right(right) {
+ }
const Node& left;
const Node& right;
diff --git a/doc/modules/ROOT/pages/basics.adoc b/doc/modules/ROOT/pages/basics.adoc
index 0d50f66d..95a9fbea 100644
--- a/doc/modules/ROOT/pages/basics.adoc
+++ b/doc/modules/ROOT/pages/basics.adoc
@@ -83,6 +83,13 @@ direct base of a class must appear together with it in at least one call to
`BOOST_OPENMETHOD_CLASSES`. This enables the library to deduce the complete
inheritance lattice.
+[NOTE]
+====
+With a compiler that supports C++26 reflection, the class list is unnecessary.
+xref:reference:BOOST_OPENMETHOD_REGISTER_CLASSES.adoc[BOOST_OPENMETHOD_REGISTER_CLASSES]
+finds the classes on its own - see <>.
+====
+
The constructs used in this example require the classes to be polymorphic, in
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.
@@ -107,3 +114,102 @@ Putting it all together:
----
include::{examplesdir}/ast.cpp[tag=content]
----
+
+
+[#registering_classes_by_reflection]
+## Registering Classes by Reflection
+
+When the compiler supports C++26 reflection (P2996), the library can work out
+the class list for itself. One call to
+xref:reference:BOOST_OPENMETHOD_REGISTER_CLASSES.adoc[BOOST_OPENMETHOD_REGISTER_CLASSES]
+replaces every
+xref:reference:BOOST_OPENMETHOD_CLASSES.adoc[BOOST_OPENMETHOD_CLASSES] in the
+file:
+
+[source,c++]
+----
+struct Animal { virtual ~Animal() = default; };
+struct Cat : Animal {};
+struct Dog : Animal {};
+struct Bulldog : Dog {};
+
+BOOST_OPENMETHOD(poke, (std::ostream&, virtual_), void);
+
+BOOST_OPENMETHOD_OVERRIDE(poke, (std::ostream& os, Dog&), void) {
+ os << "bark";
+}
+
+BOOST_OPENMETHOD_REGISTER_CLASSES(^^::); // registers all four classes
+----
+
+The macro scans the namespaces it is given - and the namespaces nested in them
+- for the methods of the registry. It collects the classes those methods
+dispatch on, then registers them, along with every class in the scanned
+namespaces that derives from one of them. `Bulldog` above has no overrider of
+its own and is named nowhere, and is registered all the same.
+
+The arguments come in four groups, each optional, in this order: reflections of
+namespaces to scan; reflections of classes to register; one value combining
+`register_classes_opts` options with `|`; and reflections of registries to register
+the classes in - `boost::openmethod::default_registry` when none is named. A
+listed class is registered whether a method dispatches on it or not, along with
+the classes the scan finds derive from it. With classes but no namespace,
+nothing is scanned: exactly the listed classes are registered, with the
+inheritance relations between them read from reflection. With neither -
+`BOOST_OPENMETHOD_REGISTER_CLASSES()` - the enclosing namespace is scanned.
+
+A base class that no method dispatches on, and that is not listed, is *not*
+registered - it could never be selected on, and registering it would cost a
+lattice node, a hash slot and dispatch table space for nothing. So a hierarchy
+rooted in some general-purpose base contributes only the part of itself that
+takes part in dispatch. As soon as another method does dispatch on that base,
+it is registered, and the inheritance edges through it with it.
+
+A scan does not enter the `std` and `boost` namespaces, so `^^::` costs little
+more than a narrower namespace would - a method cannot dispatch on a class the
+program never heard of anyway. The `register_classes_opts::scan_std` and
+`register_classes_opts::scan_boost` options bring them back in; a namespace *listed*
+explicitly is always scanned. `register_classes_opts::no_recurse` restricts the scan
+to the members declared directly in the listed namespaces.
+
+Reflection sees only what precedes it, so the macro must come *after* the
+declarations it is meant to find. Putting it at the bottom of the file is the
+simplest way to be sure.
+
+Virtual and multiple inheritance are supported. Unlike
+`BOOST_OPENMETHOD_CLASSES`, which rejects it, repeated inheritance is not an
+error here: an ambiguous base cannot take part in dispatch, so it is left out.
+
+Without reflection - in C++17, or in C++26 without the compiler flag that enables
+it - the macro expands to nothing. A file that also calls
+`BOOST_OPENMETHOD_CLASSES` therefore builds under either standard.
+
+### What Reflection Cannot Find
+
+A method is found through any declaration that names its `method` type: the
+alias `BOOST_OPENMETHOD` declares alongside the method, a `using` declaration of
+your own, or any of the method's registrar objects. None of those depends on the
+method having an overrider, so a method declared with `BOOST_OPENMETHOD` is
+always found.
+
+Three situations remain outside the scan's reach, and need a
+`BOOST_OPENMETHOD_CLASSES` of their own:
+
+* a class in a namespace the macro does not scan;
+* a core API method whose `method<...>` type is spelled out in full at every
+ use, with no `using` declaration of its own and no overrider - nothing names
+ it;
+* a program that declares no method at all, and uses `virtual_ptr` on its own -
+ there is no virtual parameter for the scan to start from.
+
+### Turning It Off
+
+Adding the `policies::explicit_class_registration` policy to a registry stops
+the library from registering anything on its own, in C++26 as in C++17:
+
+[source,c++]
+----
+struct my_registry
+ : boost::openmethod::default_registry::with<
+ boost::openmethod::policies::explicit_class_registration> {};
+----
diff --git a/doc/modules/ROOT/pages/core_api.adoc b/doc/modules/ROOT/pages/core_api.adoc
index 9d67461a..f1b3efc0 100644
--- a/doc/modules/ROOT/pages/core_api.adoc
+++ b/doc/modules/ROOT/pages/core_api.adoc
@@ -78,6 +78,23 @@ We register the classes with `use_classes`:
include::{example}/core_api.cpp[tag=use_classes]
----
+With a compiler that supports C++26 reflection, `register_classes` replaces that
+list. It scans one or more namespaces for the registry's methods, and registers
+the classes they dispatch on along with everything in those namespaces that
+derives from them:
+
+[source,c++]
+----
+BOOST_OPENMETHOD_REGISTER(register_classes<^^::>);
+----
+
+A method declared the way `postfix` is above - an alias for a `method`
+specialization - is found directly, and so is any of its `override` registrars.
+Reflection sees only what precedes it, so this must come after the declarations
+it is meant to find. See
+xref:ROOT:basics.adoc#registering_classes_by_reflection[Registering Classes by
+Reflection].
+
Finally, we call the method via the static member of the method class `fn`:
[source,c++]
diff --git a/doc/modules/ROOT/pages/ref_macros.adoc b/doc/modules/ROOT/pages/ref_macros.adoc
index c3250ee9..cf1513cd 100644
--- a/doc/modules/ROOT/pages/ref_macros.adoc
+++ b/doc/modules/ROOT/pages/ref_macros.adoc
@@ -14,6 +14,8 @@ uses of the library.
| Adds an overrider to a method.
| xref:reference:BOOST_OPENMETHOD_CLASSES.adoc[*BOOST_OPENMETHOD_CLASSES*]
| Registers classes.
+| xref:reference:BOOST_OPENMETHOD_REGISTER_CLASSES.adoc[*BOOST_OPENMETHOD_REGISTER_CLASSES*]
+| Registers the classes of a namespace, by reflection.
| xref:reference:BOOST_OPENMETHOD_INLINE_OVERRIDE.adoc[BOOST_OPENMETHOD_INLINE_OVERRIDE]
| Adds an overrider to a method as an inline function.
| xref:reference:BOOST_OPENMETHOD_DECLARE_OVERRIDER.adoc[BOOST_OPENMETHOD_DECLARE_OVERRIDER]
diff --git a/doc/modules/ROOT/pages/registries_and_policies.adoc b/doc/modules/ROOT/pages/registries_and_policies.adoc
index e7e0002e..bfd16427 100644
--- a/doc/modules/ROOT/pages/registries_and_policies.adoc
+++ b/doc/modules/ROOT/pages/registries_and_policies.adoc
@@ -92,6 +92,15 @@ is defined, `default_registry` also contains the `runtime_checks` policy. This
enables extra validations during method dispatch, which can detect missing class
registrations that could not be caught by `initialize`.
+The `explicit_class_registration` policy does the opposite of adding a
+behaviour: it stops the library from registering classes by reflection, so a
+registry that contains it knows only the classes named in
+xref:reference:BOOST_OPENMETHOD_CLASSES.adoc[BOOST_OPENMETHOD_CLASSES] or
+xref:reference:use_classes.adoc[use_classes]. It has no effect if the compiler
+does not support C++26 reflection. See
+xref:ROOT:basics.adoc#registering_classes_by_reflection[Registering Classes by
+Reflection].
+
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
diff --git a/doc/modules/ROOT/snippets/CMakeLists.txt b/doc/modules/ROOT/snippets/CMakeLists.txt
index 1b7b8c3e..de47749b 100644
--- a/doc/modules/ROOT/snippets/CMakeLists.txt
+++ b/doc/modules/ROOT/snippets/CMakeLists.txt
@@ -23,6 +23,7 @@ foreach (cpp ${cpp_files})
get_filename_component(stem ${cpp} NAME_WE)
set(test_target "boost_openmethod-snippet_${stem}")
add_executable(${test_target} ${cpp})
+ boost_openmethod_enable_reflection(${test_target})
target_link_libraries(${test_target} PRIVATE Boost::openmethod Boost::unit_test_framework)
add_test(NAME ${test_target} COMMAND ${test_target})
add_dependencies(tests ${test_target})
diff --git a/doc/modules/ROOT/snippets/errors_missing_base.cpp b/doc/modules/ROOT/snippets/errors_missing_base.cpp
index fc557b5e..20288f4f 100644
--- a/doc/modules/ROOT/snippets/errors_missing_base.cpp
+++ b/doc/modules/ROOT/snippets/errors_missing_base.cpp
@@ -3,6 +3,8 @@
// See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
+#include "explicit_registration.hpp"
+
#include
#include
diff --git a/doc/modules/ROOT/snippets/errors_missing_class_call.cpp b/doc/modules/ROOT/snippets/errors_missing_class_call.cpp
index 5f6a2bc1..9b5d42f3 100644
--- a/doc/modules/ROOT/snippets/errors_missing_class_call.cpp
+++ b/doc/modules/ROOT/snippets/errors_missing_class_call.cpp
@@ -7,6 +7,8 @@
// which `default_registry` carries only when this symbol is defined.
#define BOOST_OPENMETHOD_ENABLE_RUNTIME_CHECKS
+#include "explicit_registration.hpp"
+
#include
#include
diff --git a/doc/modules/ROOT/snippets/errors_missing_class_method.cpp b/doc/modules/ROOT/snippets/errors_missing_class_method.cpp
index 4c4095c5..e47d28ba 100644
--- a/doc/modules/ROOT/snippets/errors_missing_class_method.cpp
+++ b/doc/modules/ROOT/snippets/errors_missing_class_method.cpp
@@ -3,6 +3,8 @@
// See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
+#include "explicit_registration.hpp"
+
#include
#include
diff --git a/doc/modules/ROOT/snippets/errors_missing_class_overrider.cpp b/doc/modules/ROOT/snippets/errors_missing_class_overrider.cpp
index 31ad6bbb..65652dfa 100644
--- a/doc/modules/ROOT/snippets/errors_missing_class_overrider.cpp
+++ b/doc/modules/ROOT/snippets/errors_missing_class_overrider.cpp
@@ -3,6 +3,8 @@
// See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
+#include "explicit_registration.hpp"
+
#include
#include
diff --git a/doc/modules/ROOT/snippets/explicit_registration.hpp b/doc/modules/ROOT/snippets/explicit_registration.hpp
new file mode 100644
index 00000000..9dd08535
--- /dev/null
+++ b/doc/modules/ROOT/snippets/explicit_registration.hpp
@@ -0,0 +1,27 @@
+// Copyright (c) 2017-2026 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)
+
+// Makes the default registry require explicit class registration, so that the
+// error snippets keep reporting the error they illustrate when the compiler
+// supports C++26 reflection. Include *before* . Like
+// error_harness.hpp, never part of a tagged region: the pages show the mistake
+// and the operation that reports it, and nothing else.
+//
+// The errors themselves do not go away in C++26 -- a class the library cannot
+// reach from a method signature, an overrider, or a virtual_ptr still has to be
+// registered by hand -- but these particular examples are all within its reach.
+
+#ifndef BOOST_OPENMETHOD_SNIPPETS_EXPLICIT_REGISTRATION_HPP
+#define BOOST_OPENMETHOD_SNIPPETS_EXPLICIT_REGISTRATION_HPP
+
+#include
+
+struct snippet_registry :
+ boost::openmethod::default_registry::with<
+ boost::openmethod::policies::explicit_class_registration> {};
+
+#define BOOST_OPENMETHOD_DEFAULT_REGISTRY snippet_registry
+
+#endif
diff --git a/doc/modules/ROOT/snippets/policies.cpp b/doc/modules/ROOT/snippets/policies.cpp
index efbfde23..3a92eb4d 100644
--- a/doc/modules/ROOT/snippets/policies.cpp
+++ b/doc/modules/ROOT/snippets/policies.cpp
@@ -31,9 +31,10 @@ struct Dog : Animal {};
namespace std_rtti_demo {
// tag::std_rtti[]
-struct dynamic_registry : registry<
- policies::std_rtti, policies::fast_perfect_hash,
- policies::vptr_vector> {};
+struct dynamic_registry :
+ registry<
+ policies::std_rtti, policies::fast_perfect_hash,
+ policies::vptr_vector> {};
// end::std_rtti[]
BOOST_OPENMETHOD_CLASSES(Animal, Cat, Dog, dynamic_registry);
@@ -54,9 +55,10 @@ namespace vptr_vector_demo {
// tag::vptr_vector[]
// `fast_perfect_hash` turns the type ids into small indices; without it the
// vector is indexed by the type id itself, which `std_rtti` makes a pointer
-struct vector_registry : registry<
- policies::std_rtti, policies::fast_perfect_hash,
- policies::vptr_vector> {};
+struct vector_registry :
+ registry<
+ policies::std_rtti, policies::fast_perfect_hash,
+ policies::vptr_vector> {};
// end::vptr_vector[]
BOOST_OPENMETHOD_CLASSES(Animal, Cat, Dog, vector_registry);
@@ -97,9 +99,10 @@ namespace fast_perfect_hash_demo {
// a small integer first. With `std_rtti`, where a type id is a pointer, that
// makes the difference between a vector of a few entries and one that cannot
// be allocated at all.
-struct hashed_registry : registry<
- policies::std_rtti, policies::fast_perfect_hash,
- policies::vptr_vector> {};
+struct hashed_registry :
+ registry<
+ policies::std_rtti, policies::fast_perfect_hash,
+ policies::vptr_vector> {};
// end::fast_perfect_hash[]
BOOST_OPENMETHOD_CLASSES(Animal, Cat, Dog, hashed_registry);
@@ -118,11 +121,10 @@ BOOST_OPENMETHOD_OVERRIDE(
namespace stderr_output_demo {
// tag::stderr_output[]
-struct noisy_registry
- : registry<
- policies::std_rtti, policies::fast_perfect_hash,
- policies::vptr_vector, policies::default_error_handler,
- policies::stderr_output> {};
+struct noisy_registry :
+ registry<
+ policies::std_rtti, policies::fast_perfect_hash, policies::vptr_vector,
+ policies::default_error_handler, policies::stderr_output> {};
// end::stderr_output[]
BOOST_OPENMETHOD_CLASSES(Animal, Cat, Dog, noisy_registry);
@@ -140,11 +142,10 @@ BOOST_OPENMETHOD_OVERRIDE(
namespace default_error_handler_demo {
// tag::default_error_handler_registry[]
-struct handled_registry
- : registry<
- policies::std_rtti, policies::fast_perfect_hash,
- policies::vptr_vector, policies::default_error_handler,
- policies::stderr_output> {};
+struct handled_registry :
+ registry<
+ policies::std_rtti, policies::fast_perfect_hash, policies::vptr_vector,
+ policies::default_error_handler, policies::stderr_output> {};
// end::default_error_handler_registry[]
BOOST_OPENMETHOD_CLASSES(Animal, Cat, Dog, handled_registry);
@@ -163,10 +164,10 @@ BOOST_OPENMETHOD_OVERRIDE(
namespace throw_error_handler_demo {
// tag::throw_error_handler_registry[]
-struct throwing_registry
- : registry<
- policies::std_rtti, policies::fast_perfect_hash,
- policies::vptr_vector, policies::throw_error_handler> {};
+struct throwing_registry :
+ registry<
+ policies::std_rtti, policies::fast_perfect_hash, policies::vptr_vector,
+ policies::throw_error_handler> {};
// end::throw_error_handler_registry[]
BOOST_OPENMETHOD_CLASSES(Animal, Cat, Dog, throwing_registry);
diff --git a/doc/modules/ROOT/snippets/static_rtti.cpp b/doc/modules/ROOT/snippets/static_rtti.cpp
index 31f6809c..6d447b6c 100644
--- a/doc/modules/ROOT/snippets/static_rtti.cpp
+++ b/doc/modules/ROOT/snippets/static_rtti.cpp
@@ -13,8 +13,8 @@ struct static_registry;
#include
#include
-struct static_registry
- : boost::openmethod::registry {};
+struct static_registry :
+ boost::openmethod::registry {};
// end::registry[]
#include
diff --git a/doc/modules/ROOT/snippets/type_erasure_concept.cpp b/doc/modules/ROOT/snippets/type_erasure_concept.cpp
index aa886412..8052673d 100644
--- a/doc/modules/ROOT/snippets/type_erasure_concept.cpp
+++ b/doc/modules/ROOT/snippets/type_erasure_concept.cpp
@@ -29,9 +29,10 @@ struct Dog {
// The concept must name the Concept it is part of, so the Concept is
// defined as a struct.
-struct Dispatchable : boost::mpl::vector<
- te::copy_constructible<>, te::relaxed,
- openmethod_vptr> {};
+struct Dispatchable :
+ boost::mpl::vector<
+ te::copy_constructible<>, te::relaxed, openmethod_vptr> {
+};
using erased = te::any;
diff --git a/include/boost/openmethod/core.hpp b/include/boost/openmethod/core.hpp
index 0ffdafc1..455e94c8 100644
--- a/include/boost/openmethod/core.hpp
+++ b/include/boost/openmethod/core.hpp
@@ -22,6 +22,7 @@
#include
#include
+#include
#ifndef BOOST_OPENMETHOD_DEFAULT_REGISTRY
//! Default value for `Registry`.
@@ -210,8 +211,8 @@ struct requires_dynamic_cast_ref_aux : std::true_type {};
template
struct requires_dynamic_cast_ref_aux<
- B, D, std::void_t(std::declval()))>>
- : std::false_type {};
+ B, D, std::void_t(std::declval()))>> :
+ std::false_type {};
template
constexpr bool requires_dynamic_cast =
@@ -424,10 +425,10 @@ template
struct use_class_aux;
template
-struct use_class_aux>
- : std::conditional_t<
- Registry::has_deferred_static_rtti, detail::deferred_class_info,
- detail::class_info> {
+struct use_class_aux> :
+ std::conditional_t<
+ Registry::has_deferred_static_rtti, detail::deferred_class_info,
+ detail::class_info> {
static type_id bases[sizeof...(Bases)];
use_class_aux() {
this->first_base = bases;
@@ -500,6 +501,33 @@ class use_classes {
detail::use_classes_tuple_type tuple;
};
+// -----------------------------------------------------------------------------
+// reflection-based class registration
+
+namespace detail {
+
+#if BOOST_OPENMETHOD_HAS_REFLECTION
+
+// One registrar per entry, for the whole program - not per translation unit, as
+// `BOOST_OPENMETHOD_CLASSES` produces. Same mechanism as
+// `inplace_vptr_use_classes`: an `inline` variable template, instantiated by
+// odr-use. Keyed on the entry rather than on the class, because a class' base
+// list depends on what else was registered alongside it.
+template
+inline use_class_aux reflected_class_registrar;
+
+// Register every class the scan selected, each with its direct bases, as
+// `reflected_registered_classes` computed them.
+template
+BOOST_FORCEINLINE auto use_reflected_classes(mp11::mp_list*)
+ -> void {
+ (..., (void)&reflected_class_registrar);
+}
+
+#endif
+
+} // namespace detail
+
// =============================================================================
// virtual_ptr
@@ -550,8 +578,8 @@ template
struct is_smart_ptr_aux<
Class, Registry,
std::void_t<
- typename virtual_traits::template rebind>>
- : std::true_type {};
+ typename virtual_traits::template rebind>> :
+ std::true_type {};
template
struct same_smart_ptr_aux : std::false_type {};
@@ -560,11 +588,11 @@ template
struct same_smart_ptr_aux<
Class, Other, Registry,
std::void_t::template rebind<
- typename Other::element_type>>>
- : std::is_same<
- Other,
- typename virtual_traits::template rebind<
- typename Other::element_type>> {};
+ typename Other::element_type>>> :
+ std::is_same<
+ Other,
+ typename virtual_traits::template rebind<
+ typename Other::element_type>> {};
} // namespace detail
@@ -622,19 +650,19 @@ template
struct is_virtual&> : std::true_type {};
template
-struct is_virtual&> : std::true_type {
-};
+struct is_virtual&> :
+ std::true_type {};
template
struct is_virtual_ptr_aux : std::false_type {};
template
-struct is_virtual_ptr_aux> : std::true_type {
-};
+struct is_virtual_ptr_aux> :
+ std::true_type {};
template
-struct is_virtual_ptr_aux&>
- : std::true_type {};
+struct is_virtual_ptr_aux&> :
+ std::true_type {};
template
constexpr bool is_virtual_ptr = detail::is_virtual_ptr_aux::value;
@@ -660,9 +688,8 @@ decltype(auto) acquire_vptr(const ArgType& arg) {
Registry::require_initialized();
- if constexpr (has_vptr<
- virtual_traits,
- const ArgType&>) {
+ if constexpr (
+ has_vptr, const ArgType&>) {
return virtual_traits::vptr(arg);
} else {
return Registry::template policy::dynamic_vptr(arg);
@@ -872,9 +899,9 @@ class virtual_ptr {
//! include:virtual_ptr.cpp#ctor_nullptr
//!
//! @param value A `nullptr`.
- explicit virtual_ptr(std::nullptr_t)
- : vp(detail::box_vptr(detail::null_vptr)),
- obj(nullptr) {
+ explicit virtual_ptr(std::nullptr_t) :
+ vp(detail::box_vptr(detail::null_vptr)),
+ obj(nullptr) {
}
//! Construct a `virtual_ptr` from a reference to an object
@@ -908,10 +935,10 @@ class virtual_ptr {
BOOST_OPENMETHOD_UNLESS_MRDOCS(detail::)
IsPolymorphic &&
std::is_constructible_v>>
- virtual_ptr(Other& other)
- : vp(detail::box_vptr(
- detail::acquire_vptr(other))),
- obj(&other) {
+ virtual_ptr(Other& other) :
+ vp(detail::box_vptr(
+ detail::acquire_vptr(other))),
+ obj(&other) {
}
//! Construct a `virtual_ptr` from a pointer to an object
@@ -947,10 +974,10 @@ class virtual_ptr {
BOOST_OPENMETHOD_UNLESS_MRDOCS(detail::)
IsPolymorphic &&
std::is_constructible_v>>
- virtual_ptr(Other* other)
- : vp(detail::box_vptr(
- detail::acquire_vptr(*other))),
- obj(other) {
+ virtual_ptr(Other* other) :
+ vp(detail::box_vptr(
+ detail::acquire_vptr(*other))),
+ obj(other) {
}
//! Construct a `virtual_ptr` from another `virtual_ptr`
@@ -981,8 +1008,8 @@ class virtual_ptr {
class Other,
typename = std::enable_if_t::element_type*>>>
- virtual_ptr(const virtual_ptr& other)
- : vp(other.vp), obj(other.get()) {
+ virtual_ptr(const virtual_ptr& other) :
+ vp(other.vp), obj(other.get()) {
}
//! Assign a `virtual_ptr` from a reference to an object
@@ -1213,8 +1240,8 @@ class virtual_ptr<
}
template
- virtual_ptr(Arg&& obj, decltype(vp) vp)
- : vp(vp), obj(std::forward(obj)) {
+ virtual_ptr(Arg&& obj, decltype(vp) vp) :
+ vp(vp), obj(std::forward(obj)) {
}
public:
@@ -1228,8 +1255,8 @@ class virtual_ptr<
//!
//! @par Example
//! include:virtual_ptr.cpp#non_polymorphic_classes;shared_ctor_default
- virtual_ptr()
- : vp(detail::box_vptr(detail::null_vptr)) {
+ virtual_ptr() :
+ vp(detail::box_vptr(detail::null_vptr)) {
}
//! Construct from `nullptr`
@@ -1241,17 +1268,16 @@ class virtual_ptr<
//! include:virtual_ptr.cpp#non_polymorphic_classes;shared_ctor_nullptr
//!
//! @param value A `nullptr`.
- explicit virtual_ptr(std::nullptr_t)
- : vp(detail::box_vptr(detail::null_vptr)) {
+ explicit virtual_ptr(std::nullptr_t) :
+ vp(detail::box_vptr(detail::null_vptr)) {
}
virtual_ptr(const virtual_ptr& other) = default;
- virtual_ptr(virtual_ptr&& other)
- : vp(std::exchange(
- other.vp,
- detail::box_vptr(detail::null_vptr))),
- obj(std::move(other.obj)) {
+ virtual_ptr(virtual_ptr&& other) :
+ vp(std::exchange(
+ other.vp, detail::box_vptr(detail::null_vptr))),
+ obj(std::move(other.obj)) {
}
//! Construct from a (const) smart pointer to a derived class
@@ -1284,11 +1310,11 @@ class virtual_ptr<
std::is_constructible_v>,
typename = std::enable_if_t>>
- virtual_ptr(const Other& other)
- : vp(detail::box_vptr(
- other ? detail::acquire_vptr(*other)
- : detail::null_vptr)),
- obj(other) {
+ virtual_ptr(const Other& other) :
+ vp(detail::box_vptr(
+ other ? detail::acquire_vptr(*other)
+ : detail::null_vptr)),
+ obj(other) {
}
//! Construct from a smart pointer to a derived class
@@ -1313,11 +1339,11 @@ class virtual_ptr<
std::is_constructible_v>,
typename = std::enable_if_t>>
- virtual_ptr(Other& other)
- : vp(detail::box_vptr(
- other ? detail::acquire_vptr(*other)
- : detail::null_vptr)),
- obj(other) {
+ virtual_ptr(Other& other) :
+ vp(detail::box_vptr(
+ other ? detail::acquire_vptr(*other)
+ : detail::null_vptr)),
+ obj(other) {
}
//! Move-construct from a smart pointer to a derived class
@@ -1349,11 +1375,11 @@ class virtual_ptr<
std::is_constructible_v>,
typename = std::enable_if_t>>
- virtual_ptr(Other&& other)
- : vp(detail::box_vptr(
- other ? detail::acquire_vptr(*other)
- : detail::null_vptr)),
- obj(std::move(other)) {
+ virtual_ptr(Other&& other) :
+ vp(detail::box_vptr(
+ other ? detail::acquire_vptr(*other)
+ : detail::null_vptr)),
+ obj(std::move(other)) {
}
//! Construct from a smart virtual (const) pointer to a derived class
@@ -1377,8 +1403,8 @@ class virtual_ptr<
BOOST_OPENMETHOD_UNLESS_MRDOCS(detail::)
SameSmartPtr &&
std::is_constructible_v>>
- virtual_ptr(const virtual_ptr& other)
- : vp(other.vp), obj(other.obj) {
+ virtual_ptr(const virtual_ptr& other) :
+ vp(other.vp), obj(other.obj) {
}
//! Construct-move from a virtual pointer to a derived class
@@ -1410,11 +1436,10 @@ class virtual_ptr<
BOOST_OPENMETHOD_UNLESS_MRDOCS(detail::)
SameSmartPtr &&
std::is_constructible_v>>
- virtual_ptr(virtual_ptr&& other)
- : vp(std::exchange(
- other.vp,
- detail::box_vptr(detail::null_vptr))),
- obj(std::move(other.obj)) {
+ virtual_ptr(virtual_ptr&& other) :
+ vp(std::exchange(
+ other.vp, detail::box_vptr(detail::null_vptr))),
+ obj(std::move(other.obj)) {
}
//! Assign from `nullptr`
@@ -1766,8 +1791,8 @@ struct virtual_traits, Registry> {
//! @return A lvalue reference to a `virtual_ptr` to the same object, cast
//! to `Derived::element_type`.
template
- static auto
- cast(const virtual_ptr& ptr) -> decltype(auto) {
+ static auto cast(const virtual_ptr& ptr)
+ -> decltype(auto) {
return ptr.template cast();
}
@@ -1812,8 +1837,8 @@ struct virtual_traits&, Registry> {
//! @return A lvalue reference to a `virtual_ptr` to the same object, cast
//! to `Derived::element_type`.
template
- static auto
- cast(const virtual_ptr& ptr) -> decltype(auto) {
+ static auto cast(const virtual_ptr& ptr)
+ -> decltype(auto) {
return ptr.template cast<
typename std::remove_reference_t::element_type>();
}
@@ -1913,12 +1938,12 @@ template
struct parameter_traits, Registry> : virtual_traits {};
template
-struct parameter_traits, Registry>
- : virtual_traits, Registry> {};
+struct parameter_traits, Registry> :
+ virtual_traits, Registry> {};
template
-struct parameter_traits&, Registry>
- : virtual_traits&, Registry> {};
+struct parameter_traits&, Registry> :
+ virtual_traits&, Registry> {};
template
constexpr bool false_t = false; // workaround before CWG2518/P2593R1
@@ -1934,10 +1959,10 @@ struct validate_method_parameter, Registry, U> : std::false_type {
template
struct validate_method_parameter<
virtual_, Registry,
- std::void_t::virtual_type>>
- : std::bool_constant<
- has_vptr_fn, Registry> ||
- Registry::rtti::template is_polymorphic>> {
+ std::void_t::virtual_type>> :
+ std::bool_constant<
+ has_vptr_fn, Registry> ||
+ Registry::rtti::template is_polymorphic>> {
static_assert(
validate_method_parameter::value,
"virtual_<> parameter is not a polymorphic class and no "
@@ -1945,8 +1970,8 @@ struct validate_method_parameter<
};
template
-struct validate_method_parameter, Registry, void>
- : std::true_type {};
+struct validate_method_parameter, Registry, void> :
+ std::true_type {};
template
struct validate_method_parameter<
@@ -2060,8 +2085,8 @@ class method;
//! @tparam Registry The registry of the method
template<
typename Id, typename... Parameters, typename ReturnType, class Registry>
-class method
- : public detail::method_base {
+class method :
+ public detail::method_base {
// Deliberately no default for Inline: giving it a default on only one of
// this template's two forward declarations in this file (the other is
// below, next to override_impl) is accepted by gcc but rejected by clang
@@ -2239,8 +2264,8 @@ class method
template
auto resolve_multi_first(
- const ArgType& arg,
- const MoreArgTypes&... more_args) const -> detail::word;
+ const ArgType& arg, const MoreArgTypes&... more_args) const
+ -> detail::word;
template<
std::size_t VirtualArg, typename MethodArgList, typename ArgType,
@@ -2267,25 +2292,25 @@ class method
static BOOST_NORETURN auto fn_not_implemented(
detail::remove_virtual_... args) -> ReturnType;
- static BOOST_NORETURN auto
- fn_ambiguous(detail::remove_virtual_... args) -> ReturnType;
+ static BOOST_NORETURN auto fn_ambiguous(
+ detail::remove_virtual_... args) -> ReturnType;
template<
auto Overrider, typename OverriderReturn,
typename... OverriderParameters>
struct thunk {
- static auto
- fn(detail::remove_virtual_... arg) -> ReturnType;
+ static auto fn(detail::remove_virtual_... arg)
+ -> ReturnType;
using OverriderVirtualParameters = detail::overrider_virtual_types<
DeclaredParameters, mp11::mp_list,
Registry>;
};
template
- struct override_impl
- : std::conditional_t<
- Registry::has_deferred_static_rtti,
- detail::deferred_overrider_info, detail::overrider_info> {
+ struct override_impl :
+ std::conditional_t<
+ Registry::has_deferred_static_rtti, detail::deferred_overrider_info,
+ detail::overrider_info> {
explicit override_impl(FunctionPointer* next = nullptr);
void resolve_type_ids();
@@ -2386,8 +2411,9 @@ method::operator()(
using namespace detail;
auto pf = resolve(args...);
- return pf(std::forward::type>(
- args)...);
+ return pf(
+ std::forward::type>(
+ args)...);
}
template<
@@ -2426,9 +2452,9 @@ BOOST_FORCEINLINE auto method::vptr(
if constexpr (detail::has_vptr_fn) {
return boost_openmethod_vptr(obj, static_cast(nullptr));
- } else if constexpr (detail::has_vptr<
- virtual_traits,
- decltype(obj)>) {
+ } else if constexpr (
+ detail::has_vptr<
+ virtual_traits, decltype(obj)>) {
return virtual_traits::vptr(obj);
} else {
return Registry::template policy::dynamic_vptr(obj);
@@ -2441,8 +2467,8 @@ template<
template
BOOST_FORCEINLINE auto
method::resolve_uni(
- const ArgType& arg,
- const MoreArgTypes&... more_args) const -> detail::word {
+ const ArgType& arg, const MoreArgTypes&... more_args) const
+ -> detail::word {
using namespace detail;
using namespace policies;
@@ -2461,8 +2487,8 @@ template<
template
BOOST_FORCEINLINE auto
method::resolve_multi_first(
- const ArgType& arg,
- const MoreArgTypes&... more_args) const -> detail::word {
+ const ArgType& arg, const MoreArgTypes&... more_args) const
+ -> detail::word {
using namespace detail;
using namespace boost::mp11;
@@ -2519,8 +2545,8 @@ method::resolve_multi_next(
template<
typename Id, typename... Parameters, typename ReturnType, class Registry>
template
-inline auto
-method::has_next() -> bool {
+inline auto method::has_next()
+ -> bool {
if (next == fn_not_implemented) {
return false;
}
@@ -2598,8 +2624,8 @@ struct validate_overrider_parameter<
template
struct validate_overrider_parameter<
- T1, T2, std::enable_if_t && !is_virtual_ptr>>
- : std::false_type {
+ T1, T2, std::enable_if_t && !is_virtual_ptr>> :
+ std::false_type {
static_assert(
false_t,
"virtual_ptr<> is required in overrider in same position as in "
@@ -2613,14 +2639,14 @@ template
struct validate_overrider_parameter, T2, void> : std::true_type {};
template
-struct validate_overrider_parameter