Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-17 08:52:04

0001 // Copyright (c) 2018-2025 Jean-Louis Leroy
0002 // Distributed under the Boost Software License, Version 1.0.
0003 // See accompanying file LICENSE_1_0.txt
0004 // or copy at http://www.boost.org/LICENSE_1_0.txt)
0005 
0006 #ifndef BOOST_OPENMETHOD_CORE_HPP
0007 #define BOOST_OPENMETHOD_CORE_HPP
0008 
0009 #include <stdint.h>
0010 #include <algorithm>
0011 #include <cstdlib>
0012 #include <tuple>
0013 #include <type_traits>
0014 #include <utility>
0015 
0016 #include <boost/assert.hpp>
0017 #include <boost/config.hpp>
0018 #include <boost/mp11/algorithm.hpp>
0019 #include <boost/mp11/bind.hpp>
0020 #include <boost/mp11/integral.hpp>
0021 #include <boost/mp11/list.hpp>
0022 
0023 #include <boost/openmethod/preamble.hpp>
0024 #include <boost/openmethod/default_registry.hpp>
0025 
0026 #ifndef BOOST_OPENMETHOD_DEFAULT_REGISTRY
0027 #define BOOST_OPENMETHOD_DEFAULT_REGISTRY ::boost::openmethod::default_registry
0028 #endif
0029 
0030 #ifdef _MSC_VER
0031 #pragma warning(push)
0032 #pragma warning(disable : 4100)
0033 #pragma warning(disable : 4646)
0034 #pragma warning(disable : 4702) // unreachable code
0035 #endif
0036 
0037 //! Top namespace of the library.
0038 namespace boost::openmethod {
0039 
0040 #ifdef __MRDOCS__
0041 #define BOOST_OPENMETHOD_OPEN_NAMESPACE_DETAIL_UNLESS_MRDOCS
0042 #define BOOST_OPENMETHOD_CLOSE_NAMESPACE_DETAIL_UNLESS_MRDOCS
0043 #define BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
0044 #else
0045 #define BOOST_OPENMETHOD_OPEN_NAMESPACE_DETAIL_UNLESS_MRDOCS namespace detail {
0046 #define BOOST_OPENMETHOD_CLOSE_NAMESPACE_DETAIL_UNLESS_MRDOCS }
0047 #define BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS detail::
0048 #endif
0049 
0050 namespace detail {
0051 using sfinae = void;
0052 }
0053 
0054 template<
0055     class Class, class Registry = BOOST_OPENMETHOD_DEFAULT_REGISTRY,
0056     typename = detail::sfinae>
0057 class virtual_ptr;
0058 
0059 // =============================================================================
0060 // Helpers
0061 
0062 namespace detail {
0063 
0064 using macro_default_registry = BOOST_OPENMETHOD_DEFAULT_REGISTRY;
0065 
0066 template<typename...>
0067 struct extract_registry;
0068 
0069 template<>
0070 struct extract_registry<> {
0071     using registry = BOOST_OPENMETHOD_DEFAULT_REGISTRY;
0072     using others = mp11::mp_list<>;
0073 };
0074 
0075 template<typename Type>
0076 struct extract_registry<Type> {
0077     using registry = std::conditional_t<
0078         is_registry<Type>, Type, BOOST_OPENMETHOD_DEFAULT_REGISTRY>;
0079     using others = std::conditional_t<
0080         is_registry<Type>, mp11::mp_list<>, mp11::mp_list<Type>>;
0081 };
0082 
0083 template<typename Type1, typename Type2, typename... MoreTypes>
0084 struct extract_registry<Type1, Type2, MoreTypes...> {
0085     static_assert(!is_registry<Type1>, "policy must be the last in the list");
0086     using registry = typename extract_registry<Type2, MoreTypes...>::registry;
0087     using others = mp11::mp_push_front<
0088         typename extract_registry<Type2, MoreTypes...>::others, Type1>;
0089 };
0090 
0091 template<class Registry, class... Class>
0092 struct init_type_ids;
0093 
0094 template<class Registry, class... Class>
0095 struct init_type_ids<Registry, mp11::mp_list<Class...>> {
0096     static auto fn(type_id* ids) {
0097         (..., (*ids++ = Registry::rtti::template static_type<Class>()));
0098         return ids;
0099     }
0100 };
0101 
0102 template<class Base, class Derived>
0103 struct is_unambiguous_accessible_base_of : std::is_base_of<Base, Derived> {
0104     static_assert(
0105         std::is_base_of_v<Base, Derived> ==
0106             std::is_convertible_v<Derived&, Base&>,
0107         "class must be an accessible unambiguous base, repeated inheritance is "
0108         "not "
0109         "supported");
0110 };
0111 
0112 // Collect the base classes of a list of classes. The result is a mp11 map that
0113 // associates each class to a list starting with the class itself, followed by
0114 // all its bases, as per std::is_base_of. Thus the list includes the class
0115 // itself at least twice: at the front, and down the list, as its own improper
0116 // base. The direct and indirect bases are all included. The runtime will
0117 // extract the direct proper bases.
0118 template<typename... Cs>
0119 using inheritance_map = mp11::mp_list<boost::mp11::mp_push_front<
0120     boost::mp11::mp_filter_q<
0121         boost::mp11::mp_bind_back<is_unambiguous_accessible_base_of, Cs>,
0122         mp11::mp_list<Cs...>>,
0123     Cs>...>;
0124 
0125 // =============================================================================
0126 // optimal_cast
0127 
0128 template<typename B, typename D, typename = void>
0129 struct requires_dynamic_cast_ref_aux : std::true_type {};
0130 
0131 template<typename B, typename D>
0132 struct requires_dynamic_cast_ref_aux<
0133     B, D, std::void_t<decltype(static_cast<D>(std::declval<B>()))>>
0134     : std::false_type {};
0135 
0136 template<class B, class D>
0137 constexpr bool requires_dynamic_cast =
0138     detail::requires_dynamic_cast_ref_aux<B, D>::value;
0139 
0140 template<class Registry, class D, class B>
0141 auto optimal_cast(B&& obj) -> decltype(auto) {
0142     if constexpr (requires_dynamic_cast<B, D>) {
0143         return Registry::rtti::template dynamic_cast_ref<D>(
0144             std::forward<B>(obj));
0145     } else {
0146         return static_cast<D>(obj);
0147     }
0148 }
0149 
0150 // =============================================================================
0151 // Common details
0152 
0153 template<typename T>
0154 struct is_virtual : std::false_type {};
0155 
0156 template<typename T>
0157 struct is_virtual<virtual_<T>> : std::true_type {};
0158 
0159 template<typename T>
0160 struct remove_virtual_aux {
0161     using type = T;
0162 };
0163 
0164 template<typename T>
0165 struct remove_virtual_aux<virtual_<T>> {
0166     using type = T;
0167 };
0168 
0169 template<typename T>
0170 using remove_virtual_ = typename remove_virtual_aux<T>::type;
0171 
0172 template<typename T, class Registry, typename = void>
0173 struct virtual_type_aux {
0174     using type = void;
0175 };
0176 
0177 template<typename T, class Registry>
0178 struct virtual_type_aux<
0179     T, Registry,
0180     std::void_t<typename virtual_traits<T, Registry>::virtual_type>> {
0181     using type = typename virtual_traits<T, Registry>::virtual_type;
0182 };
0183 
0184 template<typename T, class Registry>
0185 using virtual_type = typename virtual_type_aux<T, Registry>::type;
0186 
0187 template<typename MethodArgList>
0188 using virtual_types = boost::mp11::mp_transform<
0189     remove_virtual_, boost::mp11::mp_filter<detail::is_virtual, MethodArgList>>;
0190 
0191 } // namespace detail
0192 
0193 BOOST_OPENMETHOD_OPEN_NAMESPACE_DETAIL_UNLESS_MRDOCS
0194 
0195 //! Removes the virtual_<> decorator, if present (exposition only).
0196 //!
0197 //! Provides a nested `type` equal to `T`. The template is specialized for
0198 //! `virtual_<T>`.
0199 //!
0200 //! @tparam T A type.
0201 template<typename T>
0202 struct StripVirtualDecorator {
0203     //! Same as `T`
0204     using type = T;
0205 };
0206 
0207 //! Removes the virtual_<> decorator (exposition only).
0208 //!
0209 //! Provides a nested `type` equal to `T`.
0210 //!
0211 //! @tparam T A type.
0212 template<typename T>
0213 struct StripVirtualDecorator<virtual_<T>> {
0214     //! Same as `T`.
0215     using type = T;
0216 };
0217 
0218 BOOST_OPENMETHOD_CLOSE_NAMESPACE_DETAIL_UNLESS_MRDOCS
0219 
0220 // =============================================================================
0221 // virtual_traits
0222 
0223 //! Traits for types used as virtual parameters.
0224 //!
0225 //! `virtual_traits` must be specialized for each type that can be used as a
0226 //! virtual parameters. It enables methods to:
0227 //! @li find the type of the object the argument refers to (e.g. `Node` from
0228 //! `Node&`)
0229 //! @li obtain a non-modifiable reference to that object (e.g. a `const Node&` from
0230 //! `Node&`)
0231 //! @li cast the argument to another type (e.g. cast a `Node&` to a `Plus&`)
0232 //!
0233 //! @par Requirements
0234 //!
0235 //! Specializations of `virtual_traits` must provide the members described to
0236 //! the @ref VirtualTraits blueprint.
0237 //!
0238 //! @tparam T A type referring (in the broad sense) to an instance of a class.
0239 //! @tparam Registry A @ref registry.
0240 template<typename T, class Registry>
0241 struct virtual_traits;
0242 
0243 //! Specialize virtual_traits for lvalue reference types.
0244 //!
0245 //! @tparam Class A class type, possibly cv-qualified.
0246 //! @tparam Registry A @ref registry.
0247 template<class Class, class Registry>
0248 struct virtual_traits<Class&, Registry> {
0249     //! `Class`, stripped from cv-qualifiers.
0250     using virtual_type = std::remove_cv_t<Class>;
0251 
0252     //! Return a reference to a non-modifiable `Class` object.
0253     //! @param arg A reference to a non-modifiable `Class` object.
0254     //! @return A reference to the same object.
0255     static auto peek(const Class& arg) -> const Class& {
0256         return arg;
0257     }
0258 
0259     //! Cast to another type.
0260     //!
0261     //! Cast an object to another type. If possible, use `static_cast`.
0262     //! Otherwise, use `Registry::rtti::dynamic_cast_ref`.
0263     //!
0264     //! @tparam Derived A lvalue reference type.
0265     //! @param obj A reference to a `Class` object.
0266     //! @return A reference to the same object, cast to `Derived`.
0267     template<typename Derived>
0268     static auto cast(Class& obj) -> Derived {
0269         static_assert(std::is_lvalue_reference_v<Derived>);
0270         return detail::optimal_cast<Registry, Derived>(obj);
0271     }
0272 };
0273 
0274 //! Specialize virtual_traits for xvalue reference types.
0275 //!
0276 //! @tparam T A xvalue reference type.
0277 //! @tparam Registry A @ref registry.
0278 template<class Class, class Registry>
0279 struct virtual_traits<Class&&, Registry> {
0280     //! Same as `Class`.
0281     using virtual_type = Class;
0282 
0283     //! Return a reference to a non-modifiable `Class` object.
0284     //! @param arg A reference to a non-modifiable `Class` object.
0285     //! @return A reference to the same object.
0286     static auto peek(const Class& arg) -> const Class& {
0287         return arg;
0288     }
0289 
0290     //! Cast to another type.
0291     //!
0292     //! Cast an object to another type. If possible, use `static_cast`.
0293     //! Otherwise, use `Registry::rtti::dynamic_cast_ref`.
0294     //!
0295     //! @tparam Derived A rvalue reference type.
0296     //! @param obj A reference to a `Class` object.
0297     //! @return A reference to the same object, cast to `Derived`.
0298     template<typename Derived>
0299     static auto cast(Class&& obj) -> Derived {
0300         static_assert(std::is_rvalue_reference_v<Derived>);
0301         return detail::optimal_cast<Registry, Derived>(obj);
0302     }
0303 };
0304 
0305 //! Specialize virtual_traits for pointer types.
0306 //!
0307 //! @tparam Class A class type, possibly cv-qualified.
0308 //! @tparam Registry A @ref registry.
0309 template<class Class, class Registry>
0310 struct virtual_traits<Class*, Registry> {
0311     //! `Class`, stripped from cv-qualifiers.
0312     using virtual_type = std::remove_cv_t<Class>;
0313 
0314     //! Return a reference to a non-modifiable `Class` object.
0315     //! @param arg A pointer to a non-modifiable `Class` object.
0316     //! @return A const reference to the same object.
0317     static auto peek(const Class* arg) -> const Class& {
0318         return *arg;
0319     }
0320 
0321     //! Cast to another type.
0322     //!
0323     //! Cast an object to another type. If possible, use `static_cast`.
0324     //! Otherwise, use `Registry::rtti::dynamic_cast_ref`.
0325     //!
0326     //! @tparam Derived A pointer type.
0327     //! @param obj A pointer to a `Class` object.
0328     //! @return A pointer to the same object, cast to `Derived`.
0329     template<typename Derived>
0330     static auto cast(Class* ptr) -> Derived {
0331         static_assert(std::is_pointer_v<Derived>);
0332 
0333         if constexpr (detail::requires_dynamic_cast<Class*, Derived>) {
0334             return dynamic_cast<Derived>(ptr);
0335         } else {
0336             return static_cast<Derived>(ptr);
0337         }
0338     }
0339 };
0340 
0341 namespace detail {
0342 
0343 template<class...>
0344 struct use_class_aux;
0345 
0346 template<class Registry, class Class, typename... Bases>
0347 struct use_class_aux<Registry, mp11::mp_list<Class, Bases...>>
0348     : std::conditional_t<
0349           Registry::has_deferred_static_rtti, detail::deferred_class_info,
0350           detail::class_info> {
0351     static type_id bases[sizeof...(Bases)];
0352     use_class_aux() {
0353         this->first_base = bases;
0354         this->last_base = bases + sizeof...(Bases);
0355         this->is_abstract = std::is_abstract_v<Class>;
0356         this->static_vptr = &Registry::template static_vptr<Class>;
0357 
0358         if constexpr (!Registry::has_deferred_static_rtti) {
0359             resolve_type_ids();
0360         }
0361 
0362         Registry::classes.push_back(*this);
0363     }
0364 
0365     void resolve_type_ids() {
0366         this->type = Registry::rtti::template static_type<Class>();
0367         auto iter = bases;
0368         (..., (*iter++ = Registry::rtti::template static_type<Bases>()));
0369     }
0370 
0371     ~use_class_aux() {
0372         Registry::classes.remove(*this);
0373     }
0374 };
0375 
0376 template<class Registry, class Class, typename... Bases>
0377 type_id use_class_aux<
0378     Registry, mp11::mp_list<Class, Bases...>>::bases[sizeof...(Bases)];
0379 
0380 template<class... Classes>
0381 using use_classes_tuple_type = boost::mp11::mp_apply<
0382     std::tuple,
0383     boost::mp11::mp_transform_q<
0384         boost::mp11::mp_bind_front<
0385             detail::use_class_aux,
0386             typename detail::extract_registry<Classes...>::registry>,
0387         boost::mp11::mp_apply<
0388             detail::inheritance_map,
0389             typename detail::extract_registry<Classes...>::others>>>;
0390 
0391 } // namespace detail
0392 
0393 //! Add classes to a registry
0394 //!
0395 //! `use_classes` is a registrar class that adds one or more classes to a
0396 //! registry.
0397 //!
0398 //! Classes potentially involved in a method definition, an overrider, or a
0399 //! method call must be registered via `use_classes`. A class may be registered
0400 //! multiple times. A class and its direct bases must be listed together in one
0401 //! or more instantiations of `use_classes`.
0402 //!
0403 //! If a class is identified by different type ids in different translation
0404 //! units, it must be registered in as many translation units as necessary for
0405 //! `use_classes` to register all the type ids. This situation can occur when
0406 //! using standard RTTI, because the address of the `type_info` objects are used
0407 //! as type ids, and the standard does not guarantee that there is exactly one
0408 //! such object per class. The only such case known to the author is when using
0409 //! Windows DLLs.
0410 //!
0411 //! Virtual and multiple inheritance are supported, with the exclusion of
0412 //! repeated inheritance.
0413 template<class... Classes>
0414 class use_classes {
0415     detail::use_classes_tuple_type<Classes...> tuple;
0416 };
0417 
0418 // =============================================================================
0419 // virtual_ptr
0420 
0421 namespace detail {
0422 
0423 void boost_openmethod_vptr(...);
0424 
0425 template<typename, class, typename = void>
0426 struct is_smart_ptr_aux : std::false_type {};
0427 
0428 template<typename Class, class Registry>
0429 struct is_smart_ptr_aux<
0430     Class, Registry,
0431     std::void_t<
0432         typename virtual_traits<Class, Registry>::template rebind<Class>>>
0433     : std::true_type {};
0434 
0435 template<class Class, class Other, class Registry, typename = void>
0436 struct same_smart_ptr_aux : std::false_type {};
0437 
0438 template<class Class, class Other, class Registry>
0439 struct same_smart_ptr_aux<
0440     Class, Other, Registry,
0441     std::void_t<typename virtual_traits<Class, Registry>::template rebind<
0442         typename Other::element_type>>>
0443     : std::is_same<
0444           Other,
0445           typename virtual_traits<Class, Registry>::template rebind<
0446               typename Other::element_type>> {};
0447 
0448 } // namespace detail
0449 
0450 BOOST_OPENMETHOD_OPEN_NAMESPACE_DETAIL_UNLESS_MRDOCS
0451 
0452 //! Test if argument is polymorphic (exposition only)
0453 //!
0454 //! Evaluates to `true` if `Class` is a polymorphic type, according to the
0455 //! `rtti` policy of `Registry`.
0456 //!
0457 //! If Registry's `rtti` policy is std_rtti`, this is the same as
0458 //! `std::is_polymorphic`. However, other `rtti` policies may have a different
0459 //! view of what is polymorphic.
0460 //!
0461 //! @tparam Class A class type.
0462 //! @tparam Registry A registry.
0463 template<class Class, class Registry>
0464 constexpr bool IsPolymorphic = Registry::rtti::template is_polymorphic<Class>;
0465 
0466 //! Test if argument is a smart pointer (exposition only)
0467 //!
0468 //! Evaluates to `true` if `Class` is a smart pointer type, and false otherwise.
0469 //! `Class` is considered a smart pointer if `virtual_traits<Class, Registry>`
0470 //! exists and it defines a nested template `rebind<T>` that can be instantiated
0471 //! with `Class`.
0472 //!
0473 //! @tparam Class A class type.
0474 //! @tparam Registry A registry.
0475 template<typename Class, class Registry>
0476 constexpr bool IsSmartPtr = detail::is_smart_ptr_aux<Class, Registry>::value;
0477 
0478 //! Test if arguments are same kind of smart pointers (exposition only)
0479 //!
0480 //! Evaluates to `true` if `Class` and `Other` are both smart pointers of the
0481 //! same type.
0482 //!
0483 //! @tparam Class A class type.
0484 //! @tparam Other Another class type.
0485 //! @tparam Registry A registry.
0486 template<class Class, class Other, class Registry>
0487 constexpr bool SameSmartPtr =
0488     detail::same_smart_ptr_aux<Class, Other, Registry>::value;
0489 
0490 BOOST_OPENMETHOD_CLOSE_NAMESPACE_DETAIL_UNLESS_MRDOCS
0491 
0492 template<class Registry, typename Arg>
0493 inline auto final_virtual_ptr(Arg&& obj);
0494 
0495 namespace detail {
0496 
0497 template<class Class, class Registry>
0498 struct is_virtual<virtual_ptr<Class, Registry, void>> : std::true_type {};
0499 
0500 template<class Class, class Registry>
0501 struct is_virtual<virtual_ptr<Class, Registry, void>&> : std::true_type {};
0502 
0503 template<class Class, class Registry>
0504 struct is_virtual<const virtual_ptr<Class, Registry, void>&> : std::true_type {
0505 };
0506 
0507 template<typename>
0508 struct is_virtual_ptr_aux : std::false_type {};
0509 
0510 template<class Class, class Registry>
0511 struct is_virtual_ptr_aux<virtual_ptr<Class, Registry, void>> : std::true_type {
0512 };
0513 
0514 template<class Class, class Registry>
0515 struct is_virtual_ptr_aux<const virtual_ptr<Class, Registry, void>&>
0516     : std::true_type {};
0517 
0518 template<typename T>
0519 constexpr bool is_virtual_ptr = detail::is_virtual_ptr_aux<T>::value;
0520 
0521 template<class Class, class Registry>
0522 constexpr bool has_vptr_fn = std::is_same_v<
0523     decltype(boost_openmethod_vptr(
0524         std::declval<const Class&>(), std::declval<Registry*>())),
0525     vptr_type>;
0526 
0527 template<class Registry, class ArgType>
0528 decltype(auto) acquire_vptr(const ArgType& arg) {
0529     Registry::require_initialized();
0530 
0531     if constexpr (detail::has_vptr_fn<ArgType, Registry>) {
0532         return boost_openmethod_vptr(arg, static_cast<Registry*>(nullptr));
0533     } else {
0534         return Registry::template policy<policies::vptr>::dynamic_vptr(arg);
0535     }
0536 }
0537 
0538 template<bool Indirect>
0539 inline auto box_vptr(const vptr_type& vp) {
0540     if constexpr (Indirect) {
0541         return &vp;
0542     } else {
0543         return vp;
0544     }
0545 }
0546 
0547 inline auto unbox_vptr(vptr_type vp) {
0548     return vp;
0549 }
0550 
0551 inline auto unbox_vptr(const vptr_type* vpp) {
0552     return *vpp;
0553 }
0554 
0555 inline vptr_type null_vptr = nullptr;
0556 
0557 } // namespace detail
0558 
0559 //! Creates a `virtual_ptr` for an object of a known dynamic type.
0560 //!
0561 //! Creates a @ref virtual_ptr to an object, setting its v-table pointer
0562 //! according to the declared type of its argument. Assumes that the static and
0563 //! dynamic types are the same. Sets the v-table pointer to the
0564 //! @ref registry::static_vptr for the class.
0565 //!
0566 //! `Class` is _not_ required to be polymorphic.
0567 //!
0568 //! If runtime checks are enabled, and the argument is polymorphic, checks if
0569 //! the static and dynamic types are the same. If not, calls the error handler
0570 //! with a @ref final_error value, then terminates the program with @ref abort.
0571 //!
0572 //! @par Errors
0573 //!
0574 //! @li @ref final_error The static and dynamic types of the object are
0575 //! different.
0576 //!
0577 //! @tparam Registry A @ref registry.
0578 //! @tparam Arg The type of the argument.
0579 //! @param obj A reference to an object.
0580 //! @return A `virtual_ptr<Class, Registry>` pointing to `obj`.
0581 template<class Registry, typename Arg>
0582 inline auto final_virtual_ptr(Arg&& obj) {
0583     using namespace detail;
0584     using VirtualPtr = virtual_ptr<std::remove_reference_t<Arg>, Registry>;
0585     using Traits = virtual_traits<Arg, Registry>;
0586     using Class = typename Traits::virtual_type;
0587 
0588     static_assert(!std::is_const_v<Class>);
0589     static_assert(!std::is_volatile_v<Class>);
0590     static_assert(!std::is_reference_v<Class>);
0591     static_assert(!std::is_pointer_v<Class>);
0592 
0593     Registry::require_initialized();
0594 
0595     if constexpr (
0596         Registry::has_runtime_checks &&
0597         Registry::rtti::template is_polymorphic<Class>) {
0598 
0599         // check that dynamic type == static type
0600         auto static_type = Registry::rtti::template static_type<Class>();
0601         auto dynamic_type = Registry::rtti::dynamic_type(Traits::peek(obj));
0602 
0603         if (dynamic_type != static_type) {
0604             if constexpr (is_not_void<typename Registry::error_handler>) {
0605                 final_error error;
0606                 error.static_type = static_type;
0607                 error.dynamic_type = dynamic_type;
0608                 Registry::error_handler::error(error);
0609             }
0610 
0611             abort();
0612         }
0613     }
0614 
0615     const vptr_type& vptr = Registry::template static_vptr<Class>;
0616     BOOST_ASSERT(vptr);
0617 
0618     return VirtualPtr(
0619         std::forward<Arg>(obj),
0620         detail::box_vptr<VirtualPtr::use_indirect_vptrs>(vptr));
0621 }
0622 
0623 //! Create a `virtual_ptr` for an object of a known dynamic type.
0624 //!
0625 //! This is an overload of `final_virtual_ptr` that uses the default
0626 //! registry as the `Registry` template parameter.
0627 //!
0628 //! @see @ref final_virtual_ptr
0629 // We could give a default value to Registry in the main template, but gcc
0630 // doesn't like it.
0631 template<class Arg>
0632 inline auto final_virtual_ptr(Arg&& obj) {
0633     return final_virtual_ptr<BOOST_OPENMETHOD_DEFAULT_REGISTRY, Arg>(
0634         std::forward<Arg>(obj));
0635 }
0636 //! Wide pointer combining pointers to an object and its v-table
0637 //!
0638 //! A `virtual_ptr` is a wide pointer that combines pointers to an object and
0639 //! its v-table. Calls to methods via `virtual_ptr` are as fast as ordinary
0640 //! virtual function calls (typically two instructions).
0641 //!
0642 //! A `virtual_ptr` can be implicitly constructed from a reference, a pointer,
0643 //! or another `virtual_ptr`, provided that they are type-compatible.
0644 //!
0645 //! `virtual_ptr` has specializations that use a `std::shared_ptr` or a
0646 //! `std::unique_ptr` as the pointer to the object. The mechanism can be
0647 //! extended to other smart pointers by specializing @ref virtual_traits. A
0648 //! "plain" `virtual_ptr` can be constructed from a smart `virtual_ptr`, but not
0649 //! the other way around.
0650 //!
0651 //! The default value for `Registry` can be customized by defining the
0652 //! {{BOOST_OPENMETHOD_DEFAULT_REGISTRY}}
0653 //! preprocessor symbol.
0654 //!
0655 //! @par Requirements
0656 //!
0657 //! @li @ref virtual_traits must be specialized for `Class&`.
0658 //! @li `Class` must be a class type, possibly cv-qualified, registered in
0659 //! `Registry`.
0660 //!
0661 //! @tparam Class The class of the object, possibly cv-qualified
0662 //! @tparam Registry The registry in which `Class` is registered
0663 //! @tparam unnamed Implementation defined, use default
0664 template<class Class, class Registry, typename>
0665 class virtual_ptr {
0666 
0667     using traits = virtual_traits<Class&, Registry>;
0668 
0669 #ifndef __MRDOCS__
0670     template<class, class, typename>
0671     friend class virtual_ptr;
0672     template<class, typename Arg>
0673     friend auto final_virtual_ptr(Arg&& obj);
0674 #endif
0675 
0676     static constexpr bool is_smart_ptr = false;
0677     static constexpr bool use_indirect_vptrs = Registry::has_indirect_vptr;
0678 
0679     std::conditional_t<use_indirect_vptrs, const vptr_type*, vptr_type> vp;
0680     Class* obj;
0681 
0682     template<
0683         class Other,
0684         typename = std::enable_if_t<std::is_constructible_v<Class*, Other*>>>
0685     virtual_ptr(Other& other, decltype(vp) vp) : vp(vp), obj(&other) {
0686     }
0687 
0688   public:
0689     //! Class
0690     //!
0691     //! This is the same as `Class`.
0692     using element_type = Class;
0693 
0694     //! Default constructor
0695     //!
0696     //! @note This constructor does nothing. The state of the two pointers
0697     //! inside the object is as specified for uninitialized variables by C++.
0698     virtual_ptr() = default;
0699 
0700     //! Construct from `nullptr`
0701     //!
0702     //! Set both object and v-table pointers to `nullptr`.
0703     //!
0704     //! @param value A `nullptr`.
0705     //!
0706     //! @par Example
0707     //!
0708     //! @code
0709     //! struct Animal { virtual ~Animal() { } }; // polymorphic
0710     //! struct Dog : Animal {}; // polymorphic
0711     //! BOOST_OPENMETHOD_CLASSES(Animal, Dog);
0712     //! initialize();
0713     //!
0714     //! virtual_ptr<Dog> p{nullptr};
0715     //! BOOST_TEST(p.get() == nullptr);
0716     //! BOOST_TEST(p.vptr() == nullptr);
0717     //! @endcode
0718     //!
0719     //! @param value A `nullptr`.
0720     explicit virtual_ptr(std::nullptr_t)
0721         : vp(detail::box_vptr<use_indirect_vptrs>(detail::null_vptr)),
0722           obj(nullptr) {
0723     }
0724 
0725     //! Construct a `virtual_ptr` from a reference to an object
0726     //!
0727     //! The pointer to the v-table is obtained by calling
0728     //! @ref boost_openmethod_vptr if a suitable overload exists, or the
0729     //! @ref policies::vptr::fn::dynamic_vptr of the registry's
0730     //! `vptr` policy otherwise.
0731     //!
0732     //! @param other A reference to a polymorphic object
0733     //!
0734     //! @par Example
0735     //! @code
0736     //! struct Animal { virtual ~Animal() { } }; // polymorphic
0737     //! struct Dog : Animal {}; // polymorphic
0738     //! BOOST_OPENMETHOD_CLASSES(Animal, Dog);
0739     //! initialize();
0740     //!
0741     //! Dog snoopy;
0742     //! Animal& animal = snoopy;
0743     //!
0744     //! virtual_ptr<Animal> p = animal;
0745     //!
0746     //! BOOST_TEST(p.get() == &snoopy);
0747     //! BOOST_TEST(p.vptr() == default_registry::static_vptr<Dog>);
0748     //! @endcode
0749     //!
0750     //! @par Requirements
0751     //! @li `Other` must be a polymorphic class, according to `Registry`'s
0752     //! `rtti` policy.
0753     //! @li `Other\*` must be constructible from `Class\*`.
0754     //!
0755     //! @par Errors
0756     //!
0757     //! The following errors may occur, depending on the policies selected in
0758     //! `Registry`:
0759     //!
0760     //! @li @ref missing_class
0761     template<
0762         class Other,
0763         typename = std::enable_if_t<
0764             BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
0765                 IsPolymorphic<Other, Registry> &&
0766             std::is_constructible_v<Class*, Other*>>>
0767     virtual_ptr(Other& other)
0768         : vp(detail::box_vptr<use_indirect_vptrs>(
0769               detail::acquire_vptr<Registry>(other))),
0770           obj(&other) {
0771     }
0772 
0773     //! Construct a `virtual_ptr` from a pointer to an object
0774     //!
0775     //! The pointer to the v-table is obtained by calling
0776     //! @ref boost_openmethod_vptr if a suitable overload exists, or the
0777     //! @ref policies::vptr::fn::dynamic_vptr of the registry's
0778     //! `vptr` policy otherwise.
0779     //!
0780     //! @par Example
0781     //! @code
0782     //! struct Animal { virtual ~Animal() { } }; // polymorphic
0783     //! struct Dog : Animal {}; // polymorphic
0784     //! BOOST_OPENMETHOD_CLASSES(Animal, Dog);
0785     //! initialize();
0786     //!
0787     //! Dog snoopy;
0788     //! Animal* animal = &snoopy;
0789     //!
0790     //! virtual_ptr<Animal> p = animal;
0791     //!
0792     //! BOOST_TEST(p.get() == &snoopy);
0793     //! BOOST_TEST(p.vptr() == default_registry::static_vptr<Dog>);
0794     //! @endcode
0795     //!
0796     //! @param other A pointer to a polymorphic object
0797     //!
0798     //! @par Requirements
0799     //!
0800     //! @li `Other` must be a polymorphic class, according to `Registry`'s
0801     //! `rtti` policy.
0802     //!
0803     //! @li `Other\*` must be constructible from `Class\*`.
0804     //!
0805     //! @par Errors
0806     //!
0807     //! The following errors may occur, depending on the policies selected in
0808     //! `Registry`:
0809     //!
0810     //! @li @ref missing_class
0811     template<
0812         class Other,
0813         typename = std::enable_if_t<
0814             BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
0815                 IsPolymorphic<Class, Registry> &&
0816             std::is_constructible_v<Class*, Other*>>>
0817     virtual_ptr(Other* other)
0818         : vp(detail::box_vptr<use_indirect_vptrs>(
0819               detail::acquire_vptr<Registry>(*other))),
0820           obj(other) {
0821     }
0822 
0823     //! Construct a `virtual_ptr` from another `virtual_ptr`
0824     //!
0825     //! Copy the object and v-table pointers from `other` to `this.
0826     //!
0827     //! `Other` is _not_ required to be a pointer to a polymorphic class.
0828     //!
0829     //! @par Examples
0830     //!
0831     //! Assigning from a plain virtual_ptr:
0832     //!
0833     //! @code
0834     //! struct Animal {}; // polymorphism not required
0835     //! struct Dog : Animal {}; // polymorphism not required
0836     //! BOOST_OPENMETHOD_CLASSES(Animal, Dog);
0837     //! initialize();
0838     //!
0839     //! Dog snoopy;
0840     //! virtual_ptr<Dog> dog = final_virtual_ptr(snoopy);
0841     //! virtual_ptr<Animal> p{nullptr};
0842     //!
0843     //! p = dog;
0844     //!
0845     //! BOOST_TEST(p.get() == &snoopy);
0846     //! BOOST_TEST(p.vptr() == default_registry::static_vptr<Dog>);
0847     //! @endcode
0848     //!
0849     //! Assigning from a smart virtual_ptr:
0850     //!
0851     //! @code
0852     //! struct Animal {}; // polymorphism not required
0853     //! struct Dog : Animal {}; // polymorphism not required
0854     //! BOOST_OPENMETHOD_CLASSES(Animal, Dog);
0855     //! initialize();
0856     //!
0857     //! virtual_ptr<std::shared_ptr<Animal>> snoopy = make_shared_virtual<Dog>();
0858     //! virtual_ptr<Animal> p = snoopy;
0859     //!
0860     //! BOOST_TEST(p.get() == snoopy.get());
0861     //! BOOST_TEST(p.vptr() == default_registry::static_vptr<Dog>);
0862     //! @endcode
0863     //!
0864     //! No construction of a smart `virtual_ptr` from a plain `virtual_ptr`:
0865     //!
0866     //! @code
0867     //! static_assert(
0868     //!     std::is_constructible_v<
0869     //!         shared_virtual_ptr<Animal>, virtual_ptr<Dog>> == false);
0870     //! @endcode
0871     //!
0872     //! @param other A virtual_ptr to a type-compatible object
0873     //!
0874     //! @par Requirements
0875     //! @li `Other`\'s object pointer must be assignable to a `Class\*`.
0876     template<
0877         class Other,
0878         typename = std::enable_if_t<std::is_constructible_v<
0879             Class*, typename virtual_ptr<Other, Registry>::element_type*>>>
0880     virtual_ptr(const virtual_ptr<Other, Registry>& other)
0881         : vp(other.vp), obj(other.get()) {
0882     }
0883 
0884     //! Assign a `virtual_ptr` from a reference to an object
0885     //!
0886     //! The pointer to the v-table is obtained by calling
0887     //! @ref boost_openmethod_vptr if a suitable overload exists, or the
0888     //! @ref policies::vptr::fn::dynamic_vptr of the registry's
0889     //! `vptr` policy otherwise.
0890     //!
0891     //! @par Example
0892     //! @code
0893     //! struct Animal { virtual ~Animal() { } }; // polymorphic
0894     //! struct Dog : Animal {}; // polymorphic
0895     //! BOOST_OPENMETHOD_CLASSES(Animal, Dog);
0896     //! initialize();
0897     //!
0898     //! virtual_ptr<Animal> p{nullptr};
0899     //! Dog snoopy;
0900     //! Animal& animal = snoopy;
0901     //!
0902     //! p = animal;
0903     //!
0904     //! BOOST_TEST(p.get() == &snoopy);
0905     //! BOOST_TEST(p.vptr() == default_registry::static_vptr<Dog>);
0906     //! @endcode
0907     //!
0908     //! @param other A reference to a polymorphic object
0909     //!
0910     //! @par Requirements
0911     //!
0912     //! @li `Other` must be a polymorphic class, according to `Registry`'s
0913     //! `rtti` policy.
0914     //!
0915     //! @li `Other\*` must be constructible from `Class\*`.
0916     //!
0917     //! @par Errors
0918     //!
0919     //! The following errors may occur, depending on the policies selected in
0920     //! `Registry`:
0921     //!
0922     //! @li @ref missing_class
0923     template<
0924         class Other,
0925         typename = std::enable_if_t<
0926             BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
0927                 IsPolymorphic<Class, Registry> &&
0928             std::is_assignable_v<Class*&, Other*>>>
0929     virtual_ptr& operator=(Other& other) {
0930         obj = &other;
0931         vp = detail::box_vptr<use_indirect_vptrs>(
0932             detail::acquire_vptr<Registry>(other));
0933         return *this;
0934     }
0935 
0936     //! Assign a `virtual_ptr` from a pointer to an object
0937     //!
0938     //! The pointer to the v-table is obtained by calling
0939     //! @ref boost_openmethod_vptr if a suitable overload exists, or the
0940     //! @ref policies::vptr::fn::dynamic_vptr of the registry's
0941     //! `vptr` policy otherwise.
0942     //!
0943     //! @par Example
0944     //! @code
0945     //! struct Animal { virtual ~Animal() { } }; // polymorphic
0946     //! struct Dog : Animal {}; // polymorphic
0947     //! BOOST_OPENMETHOD_CLASSES(Animal, Dog);
0948     //! initialize();
0949     //!
0950     //! virtual_ptr<Animal> p{nullptr};
0951     //! Dog snoopy;
0952     //! Animal* animal = &snoopy;
0953     //!
0954     //! p = animal;
0955     //!
0956     //! BOOST_TEST(p.get() == &snoopy);
0957     //! BOOST_TEST(p.vptr() == default_registry::static_vptr<Dog>);
0958     //! @endcode
0959     //!
0960     //! @param other A pointer to a polymorphic object
0961     //!
0962     //! @par Requirements
0963     //! @li `Other` must be a polymorphic class, according to `Registry`'s
0964     //! `rtti` policy.
0965     //! @li `Other\*` must be constructible from `Class\*`.
0966     //!
0967     //! @par Errors
0968     //!
0969     //! The following errors may occur, depending on the policies selected in
0970     //! `Registry`:
0971     //!
0972     //! @li @ref missing_class
0973     template<
0974         class Other,
0975         typename = std::enable_if_t<
0976             BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
0977                 IsPolymorphic<Class, Registry> &&
0978             std::is_assignable_v<Class*&, Other*>>>
0979     virtual_ptr& operator=(Other* other) {
0980         obj = other;
0981         vp = detail::box_vptr<use_indirect_vptrs>(
0982             detail::acquire_vptr<Registry>(*other));
0983         return *this;
0984     }
0985 
0986     //! Assign a `virtual_ptr` from another `virtual_ptr`
0987     //!
0988     //! Copy the object and v-table pointers from `other` to `this.
0989     //!
0990     //! `Other` is _not_ required to be a pointer to a polymorphic class.
0991     //!
0992     //! @par Examples
0993     //!
0994     //! Assigning from a plain virtual_ptr:
0995     //!
0996     //! @code
0997     //! struct Animal {}; // polymorphism not required
0998     //! struct Dog : Animal {}; // polymorphism not required
0999     //! BOOST_OPENMETHOD_CLASSES(Animal, Dog);
1000     //! initialize();
1001     //!
1002     //! Dog snoopy;
1003     //! virtual_ptr<Dog> dog = final_virtual_ptr(snoopy);
1004     //! virtual_ptr<Animal> p{nullptr};
1005     //!
1006     //! p = dog;
1007     //!
1008     //! BOOST_TEST(p.get() == &snoopy);
1009     //! BOOST_TEST(p.vptr() == default_registry::static_vptr<Dog>);
1010     //! @endcode
1011     //!
1012     //! Assigning from a smart virtual_ptr:
1013     //!
1014     //! @code
1015     //! struct Animal {}; // polymorphism not required
1016     //! struct Dog : Animal {}; // polymorphism not required
1017     //! BOOST_OPENMETHOD_CLASSES(Animal, Dog);
1018     //! initialize();
1019     //!
1020     //! virtual_ptr<std::shared_ptr<Animal>> snoopy = make_shared_virtual<Dog>();
1021     //! virtual_ptr<Animal> p;
1022     //!
1023     //! p = snoopy;
1024     //!
1025     //! BOOST_TEST(p.get() == snoopy.get());
1026     //! BOOST_TEST(p.vptr() == default_registry::static_vptr<Dog>);
1027     //! @endcode
1028     //!
1029     //! No assignment from a plain `virtual_ptr` to a smart `virtual_ptr`:
1030     //!
1031     //! @code
1032     //! static_assert(
1033     //!     std::is_assignable_v<
1034     //!         shared_virtual_ptr<Animal>&, virtual_ptr<Dog>> == false);
1035     //! @endcode
1036     //!
1037     //! @param other A virtual_ptr to a type-compatible object
1038     //!
1039     //! @par Requirements
1040     //! @li `Other`\'s object pointer must be assignable to a `Class\*`.
1041     template<
1042         class Other,
1043         typename = std::enable_if_t<std::is_assignable_v<
1044             Class*&, typename virtual_ptr<Other, Registry>::element_type*>>>
1045     virtual_ptr& operator=(const virtual_ptr<Other, Registry>& other) {
1046         obj = other.get();
1047         vp = other.vp;
1048         return *this;
1049     }
1050 
1051     //! Set a `virtual_ptr` to `nullptr`
1052     //!
1053     //! Set both object and v-table pointers to `nullptr`.
1054     //!
1055     //! @par Example
1056     //! struct Animal {}; // polymorphism not required
1057     //! struct Dog : Animal {}; // polymorphism not required
1058     //! BOOST_OPENMETHOD_CLASSES(Animal, Dog);
1059     //! initialize();
1060     //!
1061     //! Dog snoopy;
1062     //! virtual_ptr<Animal> p = final_virtual_ptr(snoopy);
1063     //!
1064     //! p = nullptr;
1065     //!
1066     //! BOOST_TEST(p.get() == nullptr);
1067     //! BOOST_TEST(p.vptr() == nullptr);
1068     //!     //! @code
1069     //! @endcode
1070     virtual_ptr& operator=(std::nullptr_t) {
1071         obj = nullptr;
1072         vp = detail::box_vptr<use_indirect_vptrs>(detail::null_vptr);
1073         return *this;
1074     }
1075 
1076     //! Get a pointer to the object
1077     //!
1078     //! @return A pointer to the object
1079     auto get() const -> Class* {
1080         return obj;
1081     }
1082 
1083     //! Get a pointer to the object
1084     //!
1085     //! @return A pointer to the object
1086     auto operator->() const {
1087         return get();
1088     }
1089 
1090     //! Get a reference to the object
1091     //!
1092     //! @return A reference to the object
1093     auto operator*() const -> element_type& {
1094         return *get();
1095     }
1096 
1097     //! Get a pointer to the object
1098     //!
1099     //! @return A pointer to the object
1100     auto pointer() const -> element_type* {
1101         return obj;
1102     }
1103 
1104     //! Cast to another `virtual_ptr` type
1105     //!
1106     //! @par Example
1107     //! @code
1108     //! @endcode
1109     //!
1110     //! @tparam Other The target class of the cast
1111     //! @return A `virtual_ptr<Other, Registry>` pointing to the same object
1112     //! @par Requirements
1113     //! @li `Other` must be a base or derived class of `Class`.
1114     template<
1115         class Other,
1116         typename = std::enable_if_t<
1117             std::is_base_of_v<element_type, Other> ||
1118             std::is_base_of_v<Other, element_type>>>
1119     auto cast() const -> decltype(auto) {
1120         return virtual_ptr<Other, Registry>(
1121             traits::template cast<Other&>(*obj), vp);
1122     }
1123 
1124     //! Construct a `virtual_ptr` from a reference to an object
1125     //!
1126     //! This function forwards to @ref final_virtual_ptr.
1127     //!
1128     //! @tparam Other The type of the argument
1129     //! @param obj A reference to an object
1130     //! @return A `virtual_ptr<Class, Registry>` pointing to `obj`
1131     template<class Other>
1132     static auto final(Other&& obj) {
1133         return final_virtual_ptr<Registry>(std::forward<Other>(obj));
1134     }
1135 
1136     //! Get the v-table pointer
1137     //! @return The v-table pointer
1138     auto vptr() const {
1139         return detail::unbox_vptr(this->vp);
1140     }
1141 };
1142 
1143 //! Wide pointer combining a smart pointer to an object and a pointer to its
1144 //! v-table
1145 //!
1146 //! This specialization of `virtual_ptr` uses a smart pointer to track the
1147 //! object, instead of a plain pointer.
1148 //!
1149 //! @tparam SmartPtr A smart pointer type
1150 //! @tparam Registry The registry in which the underlying class is registered
1151 template<class SmartPtr, class Registry>
1152 class virtual_ptr<
1153     SmartPtr, Registry,
1154     std::enable_if_t<
1155         BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS IsSmartPtr<SmartPtr, Registry>>> {
1156 
1157 #ifndef __MRDOCS__
1158     template<class, class, typename>
1159     friend class virtual_ptr;
1160     template<class, typename Arg>
1161     friend auto final_virtual_ptr(Arg&& obj);
1162 #endif
1163 
1164     static constexpr bool is_smart_ptr = true;
1165     static constexpr bool use_indirect_vptrs = Registry::has_indirect_vptr;
1166 
1167     using traits = virtual_traits<SmartPtr, Registry>;
1168 
1169     std::conditional_t<use_indirect_vptrs, const vptr_type*, vptr_type> vp;
1170     SmartPtr obj;
1171 
1172     template<
1173         class Other,
1174         typename = std::enable_if_t<std::is_constructible_v<SmartPtr*, Other*>>>
1175     virtual_ptr(Other& other, decltype(vp) vp) : vp(vp), obj(&other) {
1176     }
1177 
1178     template<typename Arg>
1179     virtual_ptr(Arg&& obj, decltype(vp) vp)
1180         : vp(vp), obj(std::forward<Arg>(obj)) {
1181     }
1182 
1183   public:
1184     //! Class pointed to by SmartPtr
1185     using element_type = typename SmartPtr::element_type;
1186 
1187     //! Default constructor
1188     //!
1189     //! Construct the object pointer using its default constructor. Set the
1190     //! v-table pointer to `nullptr`.
1191     //!
1192     //! @par Example
1193     //! @code
1194     //! struct Dog {}; // polymorphism not required
1195     //! BOOST_OPENMETHOD_CLASSES(Dog);
1196     //! initialize();
1197     //!
1198     //! virtual_ptr<std::shared_ptr<Dog>> p;
1199     //! BOOST_TEST(p.get() == nullptr);
1200     //! BOOST_TEST(p.vptr() == nullptr);
1201     //! @par Example
1202     //! @endcode
1203     virtual_ptr()
1204         : vp(detail::box_vptr<use_indirect_vptrs>(detail::null_vptr)) {
1205     }
1206 
1207     //! Construct from `nullptr`
1208     //!
1209     //! Construct the object pointer using its default constructor. Set the
1210     //! v-table pointer to `nullptr`.
1211     //!
1212     //! @par Example
1213     //! @code
1214     //! struct Dog {}; // polymorphism not required
1215     //! BOOST_OPENMETHOD_CLASSES(Dog);
1216     //! initialize();
1217     //!
1218     //! virtual_ptr<std::shared_ptr<Dog>> p{nullptr};
1219     //! BOOST_TEST(p.get() == nullptr);
1220     //! BOOST_TEST(p.vptr() == nullptr);
1221     //! @endcode
1222     //!
1223     //! @param value A `nullptr`.
1224     explicit virtual_ptr(std::nullptr_t)
1225         : vp(detail::box_vptr<use_indirect_vptrs>(detail::null_vptr)) {
1226     }
1227 
1228     virtual_ptr(const virtual_ptr& other) = default;
1229 
1230     virtual_ptr(virtual_ptr&& other)
1231         : vp(std::exchange(
1232               other.vp,
1233               detail::box_vptr<use_indirect_vptrs>(detail::null_vptr))),
1234           obj(std::move(other.obj)) {
1235     }
1236 #ifdef __MRDOCS__
1237     //! Construct from a (const) smart pointer to a derived class
1238     //!
1239     //! Set the object pointer with a copy of `other`. Set the v-table pointer
1240     //! according to the dynamic type of `*other`.
1241     //!
1242     //! @par Example
1243     //! @code
1244     //! struct Animal { virtual ~Animal() { } }; // polymorphic
1245     //! struct Dog : Animal {}; // polymorphic
1246     //! BOOST_OPENMETHOD_CLASSES(Animal, Dog);
1247     //! initialize();
1248     //!
1249     //! const std::shared_ptr<Dog> snoopy = std::make_shared<Dog>();
1250     //! virtual_ptr<std::shared_ptr<Animal>> p = snoopy;
1251     //!
1252     //! BOOST_TEST(p.get() == snoopy.get());
1253     //! BOOST_TEST(p.vptr() == default_registry::static_vptr<Dog>);
1254     //! @endcode
1255     //!
1256     //! @par Requirements
1257     //! @li `SmartPtr` and `Other` must be instantiated from the same template -
1258     //! e.g. both `std::shared_ptr` or both `std::unique_ptr`.
1259     //! @li `Other` must be a smart pointer to a polymorphic class derived from
1260     //! `element_type`.
1261     //! @li `SmartPtr` must be constructible from `const Other&`.
1262     template<
1263         class Other,
1264         typename = std::enable_if_t<
1265             SameSmartPtr<SmartPtr, Other, Registry> &&
1266             IsPolymorphic<typename Other::element_type, Registry> &&
1267             std::is_constructible_v<SmartPtr, const Other&>>>
1268 #else
1269     template<
1270         class Other,
1271         typename = std::enable_if_t<
1272             detail::SameSmartPtr<SmartPtr, Other, Registry> &&
1273             detail::IsPolymorphic<typename Other::element_type, Registry> &&
1274             std::is_constructible_v<SmartPtr, const Other&>>>
1275 #endif
1276     virtual_ptr(const Other& other)
1277         : vp(detail::box_vptr<use_indirect_vptrs>(
1278               other ? detail::acquire_vptr<Registry>(*other)
1279                     : detail::null_vptr)),
1280           obj(other) {
1281     }
1282 
1283 #if __MRDOCS__
1284     //! Construct from a smart pointer to a derived class
1285     //!
1286     //! Copy object pointer from `other` to `this`. Set the v-table pointer
1287     //! according to the dynamic type of `*other`.
1288     //!
1289     //! @par Example
1290     //! @code
1291     //! struct Animal { virtual ~Animal() { } }; // polymorphic
1292     //! struct Dog : Animal {}; // polymorphic
1293     //! BOOST_OPENMETHOD_CLASSES(Animal, Dog);
1294     //! initialize();
1295     //!
1296     //! std::shared_ptr<Dog> snoopy = std::make_shared<Dog>();
1297     //! virtual_ptr<std::shared_ptr<Animal>> p = snoopy;
1298     //!
1299     //! BOOST_TEST(p.get() == snoopy.get());
1300     //! BOOST_TEST(p.vptr() == default_registry::static_vptr<Dog>);
1301     //! @endcode
1302     //!
1303     //! @par Requirements
1304     //! @li `SmartPtr` and `Other` must be instantiated from the same template -
1305     //! e.g. both `std::shared_ptr` or both `std::unique_ptr`.
1306     //! @li `Other` must be a smart pointer to a polymorphic class derived from
1307     //! `element_type`.
1308     //! @li `SmartPtr` must be constructible from `Other&`.
1309     template<
1310         class Other,
1311         typename = std::enable_if_t<
1312             SameSmartPtr<SmartPtr, Other, Registry> &&
1313             IsPolymorphic<typename Other::element_type, Registry> &&
1314             std::is_constructible_v<SmartPtr, Other&>>>
1315 #else
1316     template<
1317         class Other,
1318         typename = std::enable_if_t<
1319             detail::SameSmartPtr<SmartPtr, Other, Registry> &&
1320             detail::IsPolymorphic<typename Other::element_type, Registry> &&
1321             std::is_constructible_v<SmartPtr, Other&>>>
1322 #endif
1323     virtual_ptr(Other& other)
1324         : vp(detail::box_vptr<use_indirect_vptrs>(
1325               other ? detail::acquire_vptr<Registry>(*other)
1326                     : detail::null_vptr)),
1327           obj(other) {
1328     }
1329 
1330 #ifdef __MRDOCS__
1331     //! Move-construct from a smart pointer to a derived class
1332     //!
1333     //! Move object pointer from `other` to `this`. Set the v-table pointer
1334     //! according to the dynamic type of `*other`.
1335     //!
1336     //! @par Example
1337     //! @code
1338     //! struct Animal { virtual ~Animal() { } }; // polymorphic
1339     //! struct Dog : Animal {}; // polymorphic
1340     //! BOOST_OPENMETHOD_CLASSES(Animal, Dog);
1341     //! initialize();
1342     //!
1343     //! std::shared_ptr<Dog> snoopy = std::make_shared<Dog>();
1344     //! Dog* moving = snoopy.get();
1345     //!
1346     //! virtual_ptr<std::shared_ptr<Animal>> p = std::move(snoopy);
1347     //!
1348     //! BOOST_TEST(p.get() == moving);
1349     //! BOOST_TEST(p.vptr() == default_registry::static_vptr<Dog>);
1350     //! BOOST_TEST(snoopy.get() == nullptr);
1351     //! @endcode
1352     //!
1353     //! @par Requirements
1354     //! @li `SmartPtr` and `Other` must be instantiated from the same template -
1355     //! e.g. both `std::shared_ptr` or both `std::unique_ptr`.
1356     //! @li `Other` must be a smart pointer to a polymorphic class derived from
1357     //! `element_type`.
1358     //! @li `SmartPtr` must be constructible from `Other&&`.
1359     template<
1360         class Other,
1361         typename = std::enable_if_t<
1362             SameSmartPtr<SmartPtr, Other, Registry> &&
1363             IsPolymorphic<typename Other::element_type, Registry> &&
1364             std::is_constructible_v<SmartPtr, Other&&>>>
1365 #else
1366     template<
1367         class Other,
1368         typename = std::enable_if_t<
1369             detail::SameSmartPtr<SmartPtr, Other, Registry> &&
1370             detail::IsPolymorphic<typename Other::element_type, Registry> &&
1371             std::is_constructible_v<SmartPtr, Other&&>>>
1372 #endif
1373     virtual_ptr(Other&& other)
1374         : vp(detail::box_vptr<use_indirect_vptrs>(
1375               other ? detail::acquire_vptr<Registry>(*other)
1376                     : detail::null_vptr)),
1377           obj(std::move(other)) {
1378     }
1379 
1380     //! Construct from a smart virtual (const) pointer to a derived class
1381     //!
1382     //! Copy the object and v-table pointers from `other`.
1383     //!
1384     //! `Other` is _not_ required to be a pointer to a polymorphic class.
1385     //!
1386     //! @par Example
1387     //! @code
1388     //! struct Animal {}; // polymorphism not required
1389     //! struct Dog : Animal {}; // polymorphism not required
1390     //! BOOST_OPENMETHOD_CLASSES(Animal, Dog);
1391     //! initialize();
1392     //!
1393     //! const virtual_ptr<std::shared_ptr<Dog>> snoopy = make_shared_virtual<Dog>();
1394     //! virtual_ptr<std::shared_ptr<Animal>> p = snoopy;
1395     //!
1396     //! BOOST_TEST(snoopy.get() != nullptr);
1397     //! BOOST_TEST(p.get() == snoopy.get());
1398     //! BOOST_TEST(p.vptr() == default_registry::static_vptr<Dog>);
1399     //! @endcode
1400     //!
1401     //! @par Requirements
1402     //! @li `SmartPtr` and `Other` must be instantiated from the same template -
1403     //! e.g. both `std::shared_ptr` or both `std::unique_ptr`.
1404     //! @li `Other` must be a virtual pointer to a class derived from
1405     //! `element_type`.
1406     //! @li `SmartPtr` must be constructible from `Other&`.
1407     template<
1408         class Other,
1409         typename = std::enable_if_t<
1410             BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
1411                 SameSmartPtr<SmartPtr, Other, Registry> &&
1412             std::is_constructible_v<SmartPtr, const Other&>>>
1413     virtual_ptr(const virtual_ptr<Other, Registry>& other)
1414         : vp(other.vp), obj(other.obj) {
1415     }
1416 
1417     //! Construct-move from a virtual pointer to a derived class
1418     //!
1419     //! Move the object pointer from `other` to `this`. Copy the v-table pointer
1420     //! from `other`.
1421     //!
1422     //! `Other` is _not_ required to be a pointer to a polymorphic class.
1423     //!
1424     //! @par Example
1425     //! @code
1426     //! struct Animal {}; // polymorphism not required
1427     //! struct Dog : Animal {}; // polymorphism not required
1428     //! BOOST_OPENMETHOD_CLASSES(Animal, Dog);
1429     //! initialize();
1430     //!
1431     //! virtual_ptr<std::shared_ptr<Dog>> snoopy = make_shared_virtual<Dog>();
1432     //! Dog* dog = snoopy.get();
1433     //!
1434     //! virtual_ptr<std::shared_ptr<Animal>> p = std::move(snoopy);
1435     //!
1436     //! BOOST_TEST(p.get() == dog);
1437     //! BOOST_TEST(p.vptr() == default_registry::static_vptr<Dog>);
1438     //! BOOST_TEST(snoopy.get() == nullptr);
1439     //! @endcode
1440     //!
1441     //! @par Requirements
1442     //! @li `SmartPtr` and `Other` must be instantiated from the same template -
1443     //! e.g. both `std::shared_ptr` or both `std::unique_ptr`.
1444     //! @li `Other` must be a smart pointer to a class derived from
1445     //! `element_type`.
1446     //! @li `SmartPtr` must be constructible from `Other&&`.
1447     template<
1448         class Other,
1449         typename = std::enable_if_t<
1450             BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
1451                 SameSmartPtr<SmartPtr, Other, Registry> &&
1452             std::is_constructible_v<SmartPtr, Other&&>>>
1453     virtual_ptr(virtual_ptr<Other, Registry>&& other)
1454         : vp(std::exchange(
1455               other.vp,
1456               detail::box_vptr<use_indirect_vptrs>(detail::null_vptr))),
1457           obj(std::move(other.obj)) {
1458     }
1459 
1460     //! Assign from `nullptr`
1461     //!
1462     //! Reset the object pointer using its default constructor. Set the
1463     //! v-table pointer to `nullptr`.
1464     //!
1465     //! @par Example
1466     //! @code
1467     //! struct Dog {}; // polymorphism not required
1468     //! BOOST_OPENMETHOD_CLASSES(Dog);
1469     //! initialize();
1470     //!
1471     //! virtual_ptr<std::shared_ptr<Dog>> p = make_shared_virtual<Dog>();
1472     //!
1473     //! p = nullptr;
1474     //!
1475     //! BOOST_TEST(p.get() == nullptr);
1476     //! BOOST_TEST(p.vptr() == nullptr);
1477     //! BOOST_TEST((p == virtual_ptr<std::shared_ptr<Dog>>()));
1478     //! @endcode
1479     //!
1480     //! @param value A `nullptr`.
1481     virtual_ptr& operator=(std::nullptr_t) {
1482         obj = SmartPtr();
1483         vp = detail::box_vptr<use_indirect_vptrs>(detail::null_vptr);
1484         return *this;
1485     }
1486 
1487     //! Assign from a (const) smart pointer to a derived class
1488     //!
1489     //! Copy the object pointer from `other` to `this`. Set the v-table pointer
1490     //! according to the dynamic type of `*other`.
1491     //!
1492     //! @par Example
1493     //! @code
1494     //! virtual_ptr<std::shared_ptr<Dog>> snoopy = make_shared_virtual<Dog>();
1495     //! virtual_ptr<std::shared_ptr<Dog>> p;
1496     //!
1497     //! p = snoopy;
1498     //!
1499     //! BOOST_TEST(p.get() != nullptr);
1500     //! BOOST_TEST(p.get() == snoopy.get());
1501     //! BOOST_TEST(p.vptr() == default_registry::static_vptr<Dog>);
1502     //! BOOST_TEST(snoopy.vptr() == default_registry::static_vptr<Dog>);
1503     //! @endcode
1504     //!
1505     //! @par Requirements
1506     //! @li `SmartPtr` and `Other` must be instantiated from the same template -
1507     //! e.g. both `std::shared_ptr` or both `std::unique_ptr`.
1508     //! @li `Other` must be a smart pointer to a polymorphic class derived from
1509     //! `element_type`.
1510     //! @li `SmartPtr` must be constructible from `const Other&`.
1511     template<
1512         class Other,
1513         typename = std::enable_if_t<
1514             BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
1515                 SameSmartPtr<SmartPtr, Other, Registry> &&
1516             std::is_assignable_v<SmartPtr, const Other&> &&
1517             BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
1518                 IsPolymorphic<typename Other::element_type, Registry>>>
1519     virtual_ptr& operator=(const Other& other) {
1520         obj = other;
1521         vp = detail::box_vptr<use_indirect_vptrs>(
1522             detail::acquire_vptr<Registry>(*other));
1523         return *this;
1524     }
1525 
1526     //! Move-assign from a smart pointer to a derived class
1527     //!
1528     //! Move object pointer from `other` to `this`. Set the v-table pointer
1529     //! according to the dynamic type of `*other`.
1530     //!
1531     //! @par Example
1532     //! @code
1533     //! virtual_ptr<std::shared_ptr<Dog>> snoopy = make_shared_virtual<Dog>();
1534     //! Dog* moving = snoopy.get();
1535     //! virtual_ptr<std::shared_ptr<Dog>> p;
1536     //!
1537     //! p = std::move(snoopy);
1538     //!
1539     //! BOOST_TEST(p.get() == moving);
1540     //! BOOST_TEST(p.vptr() == default_registry::static_vptr<Dog>);
1541     //! BOOST_TEST(snoopy.get() == nullptr);
1542     //! BOOST_TEST(snoopy.vptr() == nullptr);
1543     //! @endcode
1544     //!
1545     //! @par Requirements
1546     //! @li `SmartPtr` and `Other` must be instantiated from the same template -
1547     //! e.g. both `std::shared_ptr` or both `std::unique_ptr`.
1548     //! @li `Other` must be a smart pointer to a polymorphic class derived from
1549     //! `element_type`.
1550     //! @li `SmartPtr` must be constructible from `Other&&`.
1551     template<
1552         class Other,
1553         typename = std::enable_if_t<
1554             BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
1555                 SameSmartPtr<SmartPtr, Other, Registry> &&
1556             std::is_assignable_v<SmartPtr, Other&&> &&
1557             BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
1558                 IsPolymorphic<typename Other::element_type, Registry>>>
1559     virtual_ptr& operator=(Other&& other) {
1560         vp = detail::box_vptr<use_indirect_vptrs>(
1561             other ? detail::acquire_vptr<Registry>(*other) : detail::null_vptr);
1562         obj = std::move(other);
1563         return *this;
1564     }
1565 
1566     //! Assign from a smart virtual pointer to a derived class
1567     //!
1568     //! Copy the object and v-table pointers from `other` to `this`.
1569     //!
1570     //! `Other` is _not_ required to be a pointer to a polymorphic class.
1571     //!
1572     //! @par Example
1573     //! @code
1574     //! struct Animal {}; // polymorphism not required
1575     //! struct Dog : Animal {}; // polymorphism not required
1576     //! BOOST_OPENMETHOD_CLASSES(Animal, Dog);
1577     //! initialize();
1578     //!
1579     //! virtual_ptr<std::shared_ptr<Dog>> snoopy = make_shared_virtual<Dog>();
1580     //! virtual_ptr<std::shared_ptr<Dog>> p;
1581     //!
1582     //! p = snoopy;
1583     //!
1584     //! BOOST_TEST(p.get() != nullptr);
1585     //! BOOST_TEST(p.get() == snoopy.get());
1586     //! BOOST_TEST(p.vptr() == default_registry::static_vptr<Dog>);
1587     //! BOOST_TEST(snoopy.vptr() == default_registry::static_vptr<Dog>);
1588     //! @endcode
1589     //!
1590     //! @par Requirements
1591     //! @li `SmartPtr` and `Other` must be instantiated from the same template -
1592     //! e.g. both `std::shared_ptr` or both `std::unique_ptr`.
1593     //! @li `Other` must be a virtual pointer to a class derived from
1594     //! `element_type`.
1595     //! @li `SmartPtr` must be constructible from `Other&`.
1596     template<
1597         class Other,
1598         typename = std::enable_if_t<
1599             BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
1600                 SameSmartPtr<SmartPtr, Other, Registry> &&
1601             std::is_assignable_v<SmartPtr, Other&>>>
1602     virtual_ptr& operator=(virtual_ptr<Other, Registry>& other) {
1603         obj = other.obj;
1604         vp = other.vp;
1605         return *this;
1606     }
1607 
1608     virtual_ptr& operator=(const virtual_ptr& other) = default;
1609 
1610     //! Assign from a smart virtual const pointer to a derived class
1611     //!
1612     //! Copy the object and v-table pointers from `other` to `this`.
1613     //!
1614     //! `Other` is _not_ required to be a pointer to a polymorphic class.
1615     //!
1616     //! @par Example
1617     //! @code
1618     //! struct Animal {}; // polymorphism not required
1619     //! struct Dog : Animal {}; // polymorphism not required
1620     //! BOOST_OPENMETHOD_CLASSES(Animal, Dog);
1621     //! initialize();
1622     //!
1623     //! const virtual_ptr<std::shared_ptr<Dog>> snoopy = make_shared_virtual<Dog>();
1624     //! virtual_ptr<std::shared_ptr<Dog>> p;
1625     //!
1626     //! p = snoopy;
1627     //!
1628     //! BOOST_TEST(p.get() != nullptr);
1629     //! BOOST_TEST(p.get() == snoopy.get());
1630     //! BOOST_TEST(p.vptr() == default_registry::static_vptr<Dog>);
1631     //! BOOST_TEST(snoopy.vptr() == default_registry::static_vptr<Dog>);
1632     //! @endcode
1633     //!
1634     //! @par Requirements
1635     //! @li `SmartPtr` and `Other` must be instantiated from the same template -
1636     //! e.g. both `std::shared_ptr` or both `std::unique_ptr`.
1637     //! @li `Other` must be a virtual pointer to a class derived from
1638     //! `element_type`.
1639     //! @li `SmartPtr` must be constructible from `Other&`.
1640     template<
1641         class Other,
1642         typename = std::enable_if_t<
1643             BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
1644                 SameSmartPtr<SmartPtr, Other, Registry> &&
1645             std::is_assignable_v<SmartPtr, const Other&>>>
1646     virtual_ptr& operator=(const virtual_ptr<Other, Registry>& other) {
1647         obj = other.obj;
1648         vp = other.vp;
1649         return *this;
1650     }
1651 
1652     //! Move from a virtual pointer to a derived class
1653     //!
1654     //! Move the object pointer from `other` to `this`. Copy the v-table pointer
1655     //! from `other`.
1656     //!
1657     //! `Other` is _not_ required to be a pointer to a polymorphic class.
1658     //!
1659     //! @par Example
1660     //! @code
1661     //! struct Animal {}; // polymorphism not required
1662     //! struct Dog : Animal {}; // polymorphism not required
1663     //! BOOST_OPENMETHOD_CLASSES(Animal, Dog);
1664     //! initialize();
1665     //!
1666     //! virtual_ptr<std::shared_ptr<Dog>> snoopy =
1667     //!     make_shared_virtual<Dog>();
1668     //! Dog* moving = snoopy.get();
1669     //! virtual_ptr<std::shared_ptr<Dog>> p;
1670     //!
1671     //! p = std::move(snoopy);
1672     //!
1673     //! BOOST_TEST(p.get() == moving);
1674     //! BOOST_TEST(p.vptr() == default_registry::static_vptr<Dog>);
1675     //! BOOST_TEST(snoopy.get() == nullptr);
1676     //! BOOST_TEST(snoopy.vptr() == nullptr);
1677     //! @endcode
1678     //!
1679     //! @par Requirements
1680     //! @li `SmartPtr` and `Other` must be instantiated from the same template -
1681     //! e.g. both `std::shared_ptr` or both `std::unique_ptr`.
1682     //! @li `Other` must be a smart pointer to a class derived from
1683     //! `element_type`.
1684     //! @li `SmartPtr` must be constructible from `Other&&`.
1685     template<
1686         class Other,
1687         typename = std::enable_if_t<
1688             BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
1689                 SameSmartPtr<SmartPtr, Other, Registry> &&
1690             std::is_assignable_v<SmartPtr, Other&&>>>
1691     virtual_ptr& operator=(virtual_ptr<Other, Registry>&& other) {
1692         vp = std::exchange(
1693             other.vp, detail::box_vptr<use_indirect_vptrs>(detail::null_vptr));
1694         obj = std::move(other.obj);
1695 
1696         return *this;
1697     }
1698 
1699     //! Get a pointer to the object
1700     //!
1701     //! @return A *plain* pointer to the object
1702     auto get() const -> element_type* {
1703         return obj.get();
1704     }
1705 
1706     //! Get a pointer to the object
1707     //!
1708     //! @return A *plain* pointer to the object
1709     auto operator->() const -> element_type* {
1710         return get();
1711     }
1712 
1713     //! Get a reference to the object
1714     //!
1715     //! @return A reference to the object
1716     auto operator*() const -> element_type& {
1717         return *get();
1718     }
1719 
1720     //! Get a smart pointer to the object
1721     //!
1722     //! @return A const reference to the object pointer
1723     auto pointer() const -> const SmartPtr& {
1724         return obj;
1725     }
1726 
1727     //! Cast to another `virtual_ptr` type
1728     //! @tparam Other The target class of the cast
1729     //! @return A `virtual_ptr<Other, Registry>` pointing to the same object
1730     //! @par Requirements
1731     //! @li `Other` must be a base or a derived class of `Class`.
1732     template<
1733         class Other,
1734         typename = std::enable_if_t<
1735             std::is_base_of_v<element_type, Other> ||
1736             std::is_base_of_v<Other, element_type>>>
1737     auto cast() & -> decltype(auto) {
1738         using other_smart_ptr = typename traits::template rebind<Other>;
1739 
1740         return virtual_ptr<other_smart_ptr, Registry>(
1741             traits::template cast<other_smart_ptr>(obj), vp);
1742     }
1743 
1744     template<
1745         class Other,
1746         typename = std::enable_if_t<
1747             std::is_base_of_v<element_type, Other> ||
1748             std::is_base_of_v<Other, element_type>>>
1749     auto cast() const& -> decltype(auto) {
1750         using other_smart_ptr = typename traits::template rebind<Other>;
1751 
1752         return virtual_ptr<other_smart_ptr, Registry>(
1753             traits::template cast<other_smart_ptr>(obj), vp);
1754     }
1755 
1756     template<class Other>
1757     auto cast() && -> decltype(auto) {
1758         static_assert(
1759             std::is_base_of_v<element_type, Other> ||
1760             std::is_base_of_v<Other, element_type>);
1761 
1762         using other_smart_ptr = typename traits::template rebind<Other>;
1763 
1764         return virtual_ptr<other_smart_ptr, Registry>(
1765             traits::template cast<other_smart_ptr>(std::move(obj)), vp);
1766     }
1767 
1768     //! Construct a `virtual_ptr` from a smart pointer to an object
1769     //!
1770     //! This function forwards to @ref final_virtual_ptr.
1771     //!
1772     //! @tparam Other The type of the argument
1773     //! @param obj A reference to an object
1774     //! @return A `virtual_ptr<Class, Registry>` pointing to `obj`
1775     template<class Other>
1776     static auto final(Other&& obj) {
1777         return final_virtual_ptr<Registry>(std::forward<Other>(obj));
1778     }
1779 
1780     //! Get the v-table pointer
1781     //! @return The v-table pointer
1782     auto vptr() const {
1783         return detail::unbox_vptr(this->vp);
1784     }
1785 };
1786 
1787 //! Construct a `virtual_ptr` from a lvalue reference.
1788 //!
1789 //! @tparam Class A class type, possibly cv-qualified.
1790 //! @param obj A lvalue reference to an object.
1791 //! @return A `virtual_ptr<Class>`.
1792 template<class Class>
1793 virtual_ptr(Class& obj)
1794     -> virtual_ptr<Class, BOOST_OPENMETHOD_DEFAULT_REGISTRY>;
1795 
1796 //! Construct a `virtual_ptr` from a xvalue reference.
1797 //!
1798 //! @tparam Class A class type.
1799 //! @param obj A xvalue reference to an object.
1800 //! @return A `virtual_ptr<Class>`.
1801 template<class Class>
1802 virtual_ptr(Class&& obj)
1803     -> virtual_ptr<Class, BOOST_OPENMETHOD_DEFAULT_REGISTRY>;
1804 
1805 // Alas this is not allowed:
1806 // template<class Registry, class Class>
1807 // virtual_ptr<Registry>(Class&) -> virtual_ptr<Class, Registry>;
1808 
1809 //! Compare two `virtual_ptr`s for equality.
1810 //!
1811 //! Compare the underlying object pointers for equality. The v-table pointers
1812 //! are not compared.
1813 //!!
1814 //! @tparam Left The type of the left-hand side argument.
1815 //! @tparam Right The type of the right-hand side argument.
1816 //! @tparam Registry A @ref registry.
1817 //! @param left A reference to a `virtual_ptr`.
1818 //! @param right A reference to a `virtual_ptr`.
1819 //! @return `true` if both `virtual_ptr`s point to the same object or both
1820 //! are `nullptr`, `false` otherwise.
1821 template<class Left, class Right, class Registry>
1822 auto operator==(
1823     const virtual_ptr<Left, Registry>& left,
1824     const virtual_ptr<Right, Registry>& right) -> bool {
1825     return left.pointer() == right.pointer();
1826 }
1827 
1828 //! Compare two `virtual_ptr`s for inequality.
1829 //!
1830 //! Compare the underlying object pointers for inequality. The v-table pointers
1831 //! are not compared.
1832 //!! @tparam Left The type of the left-hand side argument.
1833 //! @tparam Right The type of the right-hand side argument.
1834 //! @tparam Registry A @ref registry.
1835 //! @param left A reference to a `virtual_ptr`.
1836 //! @param right A reference to a `virtual_ptr`.
1837 //! @return `true` if both `virtual_ptr`s point to different objects, or one
1838 //! is `nullptr` and the other is not, `false` otherwise.
1839 template<class Left, class Right, class Registry>
1840 auto operator!=(
1841     const virtual_ptr<Left, Registry>& left,
1842     const virtual_ptr<Right, Registry>& right) -> bool {
1843     return !(left == right);
1844 }
1845 
1846 //! Specialize virtual_traits for `virtual_ptr`.
1847 //!
1848 //! Specialize virtual_traits for `virtual_ptr`\'s passed by value.
1849 //!
1850 //! @tparam Class A class type, possibly cv-qualified.
1851 //! @tparam Registry A @ref registry.
1852 template<class Class, class Registry>
1853 struct virtual_traits<virtual_ptr<Class, Registry>, Registry> {
1854     //! `Class`, stripped from cv-qualifiers.
1855     using virtual_type =
1856         std::remove_cv_t<typename virtual_ptr<Class, Registry>::element_type>;
1857 
1858     //! Return a reference to a non-modifiable `Class` object.
1859     //! @param arg A reference to a non-modifiable `Class` object.
1860     //! @return A reference to the same object.
1861     static auto peek(const virtual_ptr<Class, Registry>& ptr)
1862         -> const virtual_ptr<Class, Registry>& {
1863         return ptr;
1864     }
1865 
1866     //! Cast to another type.
1867     //!
1868     //! Cast a `virtual_ptr` to another type, using its `cast` member function.
1869     //!
1870     //! @param obj A lvalue reference to a `virtual_ptr`.
1871     //! @return A lvalue reference to a `virtual_ptr` to the same object, cast
1872     //! to `Derived::element_type`.
1873     template<typename Derived>
1874     static auto
1875     cast(const virtual_ptr<Class, Registry>& ptr) -> decltype(auto) {
1876         return ptr.template cast<typename Derived::element_type>();
1877     }
1878 
1879     //! Cast to another type.
1880     //!
1881     //! Cast a `virtual_ptr` to another type, using its `cast` member function.
1882     //!
1883     //! @param obj A xvalue reference to a `virtual_ptr`.
1884     //! @return A xvalue reference to a `virtual_ptr` to the same object, cast
1885     //! to `Derived::element_type`.
1886     template<typename Derived>
1887     static auto cast(virtual_ptr<Class, Registry>&& ptr) -> decltype(auto) {
1888         return std::move(ptr).template cast<typename Derived::element_type>();
1889     }
1890 };
1891 
1892 //! Specialize virtual_traits for `virtual_ptr`.
1893 //!
1894 //! Specialize virtual_traits for `virtual_ptr`\'s passed by const reference.
1895 //!
1896 //! @tparam Class A class type, possibly cv-qualified.
1897 //! @tparam Registry A @ref registry.
1898 template<class Class, class Registry>
1899 struct virtual_traits<const virtual_ptr<Class, Registry>&, Registry> {
1900     //! `Class`, stripped from cv-qualifiers.
1901     using virtual_type =
1902         std::remove_cv_t<typename virtual_ptr<Class, Registry>::element_type>;
1903 
1904     //! Return a reference to a non-modifiable `Class` object.
1905     //! @param arg A reference to a non-modifiable `Class` object.
1906     //! @return A reference to the same object.
1907     static auto peek(const virtual_ptr<Class, Registry>& ptr)
1908         -> const virtual_ptr<Class, Registry>& {
1909         return ptr;
1910     }
1911 
1912     //! Cast to another type.
1913     //!
1914     //! Cast a `virtual_ptr` to another type, using its `cast` member function.
1915     //!
1916     //! @param obj A lvalue reference to a `virtual_ptr`.
1917     //! @return A lvalue reference to a `virtual_ptr` to the same object, cast
1918     //! to `Derived::element_type`.
1919     template<typename Derived>
1920     static auto
1921     cast(const virtual_ptr<Class, Registry>& ptr) -> decltype(auto) {
1922         return ptr.template cast<
1923             typename std::remove_reference_t<Derived>::element_type>();
1924     }
1925 };
1926 
1927 // =============================================================================
1928 // Method
1929 
1930 namespace detail {
1931 
1932 template<typename P, typename Q, class Registry>
1933 struct select_overrider_virtual_type_aux {
1934     using type = void;
1935 };
1936 
1937 template<typename P, typename Q, class Registry>
1938 struct select_overrider_virtual_type_aux<virtual_<P>, Q, Registry> {
1939     using type = virtual_type<Q, Registry>;
1940 };
1941 
1942 template<typename P, typename Q, class Registry>
1943 struct select_overrider_virtual_type_aux<
1944     virtual_ptr<P, Registry>, virtual_ptr<Q, Registry>, Registry> {
1945     using type = typename virtual_traits<
1946         virtual_ptr<Q, Registry>, Registry>::virtual_type;
1947 };
1948 
1949 template<typename P, typename Q, class Registry>
1950 struct select_overrider_virtual_type_aux<
1951     const virtual_ptr<P, Registry>&, const virtual_ptr<Q, Registry>&,
1952     Registry> {
1953     using type = typename virtual_traits<
1954         const virtual_ptr<Q, Registry>&, Registry>::virtual_type;
1955 };
1956 
1957 template<typename P, typename Q, class Registry>
1958 using select_overrider_virtual_type =
1959     typename select_overrider_virtual_type_aux<P, Q, Registry>::type;
1960 
1961 template<
1962     typename MethodParameters, typename OverriderParameters, class Registry>
1963 using overrider_virtual_types = boost::mp11::mp_remove<
1964     boost::mp11::mp_transform_q<
1965         boost::mp11::mp_bind_back<select_overrider_virtual_type, Registry>,
1966         MethodParameters, OverriderParameters>,
1967     void>;
1968 
1969 template<class Method, class Rtti, std::size_t Index>
1970 struct init_bad_call {
1971     template<typename Arg, typename... Args>
1972     static auto fn(bad_call& error, const Arg& arg, const Args&... args) {
1973         if constexpr (Index == 0u) {
1974             error.method = Rtti::template static_type<Method>();
1975             error.arity = sizeof...(args) + 1;
1976         }
1977 
1978         type_id arg_type_id;
1979 
1980         if constexpr (is_virtual_ptr<Arg>) {
1981             arg_type_id = Rtti::dynamic_type(*arg);
1982         } else {
1983             arg_type_id = Rtti::dynamic_type(arg);
1984         }
1985 
1986         error.types[Index] = arg_type_id;
1987 
1988         init_bad_call<Method, Rtti, Index + 1>::fn(error, args...);
1989     }
1990 
1991     static auto fn(bad_call&) {
1992     }
1993 };
1994 
1995 template<class Method, class Rtti>
1996 struct init_bad_call<Method, Rtti, bad_call::max_types> {
1997     static auto fn(bad_call&) {
1998     }
1999 };
2000 
2001 template<class Registry>
2002 using method_base = std::conditional_t<
2003     Registry::has_deferred_static_rtti, deferred_method_info, method_info>;
2004 
2005 template<typename T, class Registry>
2006 struct parameter_traits {
2007     static auto peek(const T& value) -> const T& {
2008         return value;
2009     }
2010 
2011     template<typename>
2012     static auto cast(T value) -> T {
2013         return value;
2014     }
2015 };
2016 
2017 template<typename T, class Registry>
2018 struct parameter_traits<virtual_<T>, Registry> : virtual_traits<T, Registry> {};
2019 
2020 template<class Class, class Registry>
2021 struct parameter_traits<virtual_ptr<Class, Registry, void>, Registry>
2022     : virtual_traits<virtual_ptr<Class, Registry, void>, Registry> {};
2023 
2024 template<class Class, class Registry>
2025 struct parameter_traits<const virtual_ptr<Class, Registry, void>&, Registry>
2026     : virtual_traits<const virtual_ptr<Class, Registry, void>&, Registry> {};
2027 
2028 template<typename...>
2029 constexpr bool false_t = false; // workaround before CWG2518/P2593R1
2030 
2031 template<typename T, class Registry, typename = void>
2032 struct validate_method_parameter : std::true_type {};
2033 
2034 template<typename T, class Registry, typename U>
2035 struct validate_method_parameter<virtual_<T>, Registry, U> : std::false_type {
2036     static_assert(false_t<T>, "virtual_traits not specialized for type");
2037 };
2038 
2039 template<typename T, class Registry>
2040 struct validate_method_parameter<
2041     virtual_<T>, Registry,
2042     std::void_t<typename virtual_traits<T, Registry>::virtual_type>>
2043     : std::bool_constant<
2044           has_vptr_fn<virtual_type<T, Registry>, Registry> ||
2045           Registry::rtti::template is_polymorphic<virtual_type<T, Registry>>> {
2046     static_assert(
2047         validate_method_parameter::value,
2048         "virtual_<> parameter is not a polymorphic class and no "
2049         "boost_openmethod_vptr is applicable");
2050 };
2051 
2052 template<class Class, class Registry>
2053 struct validate_method_parameter<virtual_ptr<Class, Registry>, Registry, void>
2054     : std::true_type {};
2055 
2056 template<class Class, class Registry, class MethodRegistry>
2057 struct validate_method_parameter<
2058     virtual_ptr<Class, Registry>, MethodRegistry, void> : std::false_type {
2059     static_assert(
2060         false_t<Class, Registry, MethodRegistry>, "registry mismatch");
2061 };
2062 } // namespace detail
2063 
2064 //! Implement a method
2065 //!
2066 //! Methods are created by specializing the `method` class template with an
2067 //! identifier, a function type and optionally a registry.
2068 //!
2069 //! `Id` is a type, typically an incomplete class declaration named after the
2070 //! method's purpose. It is used to allow different methods with the same
2071 //! signature.
2072 //!
2073 //! `Fn` is a function type, i.e. a type in the form `ReturnType(Parameters...)`.
2074 //!
2075 //! `Registry` is an instantiation of class template @ref registry. Methods may
2076 //! use only classes that have been registered in the same registry as virtual
2077 //! parameters and arguments. The registry also contains a set of policies that
2078 //! influence several aspects of the dispatch mechanism - for example, how to
2079 //! acquire a v-table pointer for an object, how to report errors, whether to
2080 //! perform sanity checks, etc.
2081 //!
2082 //! The default value for `Registry` is @ref default_registry, but it can be
2083 //! overridden by defining the preprocessor symbol
2084 //! {{BOOST_OPENMETHOD_DEFAULT_REGISTRY}}, *before* including
2085 //! `<boost/openmethod/core.hpp>`. Setting the symbol afterwards has no effect.
2086 //!
2087 //! Specializations of `method` have a single instance: the static member `fn`,
2088 //! which has an `operator()` that forwards to the appropriate overrider. It is
2089 //! selected in the same way as overloaded function resolution:
2090 //!
2091 //! 1. Form the set of all applicable overriders. An overrider is applicable
2092 //!    if it can be called with the arguments passed to the method.
2093 //!
2094 //! 2. If the set is empty, call the error handler (if present in the
2095 //!    registry), then terminate the program with `abort`.
2096 //!
2097 //! 3. Remove the overriders that are dominated by other overriders in the set.
2098 //!    Overrider A dominates overrider B if at least one of its virtual formal
2099 //!    parameters is more specialized than B's, and if none of B's virtual
2100 //!    parameters is more specialized than A's.
2101 //!
2102 //! 4. If the resulting set contains exactly one overrider, call it.
2103 //!
2104 //! If a single most specialized overrider does not exist, the program is
2105 //! terminated via `abort`. If the registry contains an @ref error_handler
2106 //! policy, its `error` function is called with an object that describes the
2107 //! error, prior calling `abort`. `error` may prevent termination by throwing an
2108 //! exception.
2109 //!
2110 //! For each virtual argument `arg`, the dispatch mechanism calls
2111 //! `virtual_traits::peek(arg)` and deduces the v-table pointer from the
2112 //! `result`, using the first of the following methods that applies:
2113 //!
2114 //! 1. If `result` is a `virtual_ptr`, get the pointer to the v-table from it.
2115 //!
2116 //! 2. If `boost_openmethod_vptr` can be called with `result` and a `Registry*`,
2117 //!    and it returns a `vptr_type`, call it.
2118 //!
2119 //! 3. Call `Registry::rtti::dynamic_vptr(result)`.
2120 //!
2121 //! @par N2216 Handling of Ambiguous Calls
2122 //!
2123 //! If `Registry` was initialized with the @ref N2216 option, ambiguous calls
2124 //! are not an error. Instead, the following extra steps are taken to select an
2125 //! overrider:
2126 //!
2127 //! 1. If the return type is a registered polymorphic type, remove all the
2128 //!    overriders that return a less specific type than others.
2129 //!
2130 //! 2. If the resulting set contains only one overrider, call it.
2131 //!
2132 //! 3. Otherwise, call one of the remaining overriders. Which overrider is
2133 //!    selected is not specified, but it is the same across calls with the
2134 //!    same arguments types.
2135 //!
2136 //! @tparam Id A type
2137 //! @tparam Fn A function type
2138 //! @tparam Registry The registry in which the method is defined
2139 template<
2140     typename Id, typename Fn,
2141     class Registry = BOOST_OPENMETHOD_DEFAULT_REGISTRY>
2142 class method;
2143 
2144 //! Method with a specific id, signature and return type
2145 //!
2146 //! `method` implements an open-method that takes a parameter list -
2147 //! `Parameters` - and returns a `ReturnType`.
2148 //!
2149 //! `Parameters` must contain at least one virtual parameter, i.e. a parameter
2150 //! that has a type in the form `virtual_ptr<T, Registry>` or `virtual\_<T>`.
2151 //! The dynamic types of the virtual arguments are taken into account to select
2152 //! the overrider to call.
2153 //!
2154 //! @see method
2155 //!
2156 //! @tparam Id A type representing the method's name
2157 //! @tparam ReturnType The return type of the method
2158 //! @tparam Parameters The types of the parameters
2159 //! @tparam Registry The registry of the method
2160 template<
2161     typename Id, typename... Parameters, typename ReturnType, class Registry>
2162 class method<Id, ReturnType(Parameters...), Registry>
2163     : public detail::method_base<Registry> {
2164     template<auto Function, typename FunctionType>
2165     struct override_aux;
2166 
2167     // Aliases used in implementation only. Everything extracted from template
2168     // arguments is capitalized like the arguments themselves.
2169     using RegistryType = Registry;
2170     using rtti = typename Registry::rtti;
2171     using DeclaredParameters = mp11::mp_list<Parameters...>;
2172     using CallParameters =
2173         boost::mp11::mp_transform<detail::remove_virtual_, DeclaredParameters>;
2174     using VirtualParameters =
2175         typename detail::virtual_types<DeclaredParameters>;
2176     using Signature = auto(Parameters...) -> ReturnType;
2177     using FunctionPointer = auto (*)(detail::remove_virtual_<Parameters>...)
2178         -> ReturnType;
2179 
2180   public:
2181     //! Method singleton
2182     //!
2183     //! The only instance of `method`. Its `operator()` is used to call
2184     //! the method.
2185     static method fn;
2186 
2187     //! Call the method
2188     //!
2189     //! Call the method with `args`. The types of the arguments are the same as
2190     //! the method `Parameters...`, stripped from any `virtual\_` decorators.
2191     //!
2192     //! @param args The arguments for the method call
2193     //!
2194     //! @par Errors
2195     //!
2196     //! If `Registry` contains an @ref error_handler policy, call its `error`
2197     //! function with an object of one of the following types:
2198     //!
2199     //! @li @ref not_implemented: No overrider is applicable.
2200     //! @li @ref ambiguous_call: More than one overrider is applicable, and
2201     //! none is more specialized than all the others.
2202     //!
2203     auto operator()(typename BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
2204                         StripVirtualDecorator<Parameters>::type... args) const
2205         -> ReturnType;
2206 
2207     //! Check if a next most specialized overrider exists
2208     //!
2209     //! Return `true` if a next most specialized overrider after _Fn_ exists,
2210     //! and @ref next can be called without causing a @ref bad_call.
2211     //!
2212     //! @par Requirements
2213     //!
2214     //! `Fn` must be a function that is an overrider of the method.
2215     //!
2216     //! @tparam Fn A function that is an overrider of the method.
2217     //! @return `true` if a next most specialized overrider exists
2218     template<auto Fn>
2219     static bool has_next();
2220 
2221     //! The next most specialized overrider
2222     //!
2223     //! A pointer to the next most specialized overrider after `Fn`, i.e. the
2224     //! overrider that would be called for the same tuple of virtual arguments
2225     //! if `Fn` was not present. Set to `nullptr` if no such overrider exists.
2226     //! @par Requirements
2227     //!
2228     //! `Fn` must be a function that is an overrider of the method.
2229     //!
2230     //! @tparam Fn A function that is an overrider of the method.
2231     template<auto Fn>
2232     static FunctionPointer next;
2233 
2234     //! Add overriders to method
2235     //!
2236     //! `override`, instantiated as a static object, adds one or more overriders
2237     //! to an open-method.
2238     //!
2239     //! @par Requirements
2240     //!
2241     //! `Fn` must be a function that fulfills the following requirements:
2242     //!
2243     //! @li Have the same number of formal parameters as the method.
2244     //!
2245     //! @li Each `virtual_ptr<T>` in the method's parameter list must have a
2246     //! corresponding `virtual_ptr<U>` parameter in the same position in the
2247     //! overrider's parameter list, such that `U` is the same as `T`, or has
2248     //! `T` as an accessible unambiguous base.
2249     //!
2250     //! @li Each `virtual_<T>` in the method's parameter list must have a
2251     //! corresponding `U` parameter in the same position in the overrider's
2252     //! parameter list, such that `U` is the same as `T`, or has `T` as an
2253     //! accessible unambiguous base.
2254     //!
2255     //! @li All other formal parameters must have the same type as the method's
2256     //! corresponding parameters.
2257     //!
2258     //! @li The return type of the overrider must be the same as the method's
2259     //! return type or, if it is a polymorphic type, covariant with the method's
2260     //! return type.
2261     //!
2262     //! @tparam Fn One or more functions to the overrider list
2263     template<auto... Fn>
2264     class override {
2265         std::tuple<override_aux<Fn, decltype(Fn)>...> impl;
2266     };
2267 
2268   private:
2269     static constexpr auto Arity = boost::mp11::mp_count_if<
2270         mp11::mp_list<Parameters...>, detail::is_virtual>::value;
2271 
2272     // sanity checks
2273     static_assert((
2274         detail::validate_method_parameter<Parameters, Registry>::value && ...));
2275     static_assert(Arity > 0, "method has no virtual parameters");
2276 
2277     type_id vp_type_ids[Arity];
2278 
2279     std::size_t slots_strides[2 * Arity - 1];
2280     // Slots followed by strides. No stride for first virtual argument.
2281     // For 1-method: the offset of the method in the method table, which
2282     // contains a pointer to a function.
2283     // For multi-methods: the offset of the first virtual argument in the
2284     // method table, which contains a pointer to the corresponding cell in
2285     // the dispatch table, followed by the offset of the second argument and
2286     // the stride in the second dimension, etc.
2287 
2288     void resolve_type_ids();
2289 
2290     template<typename ArgType>
2291     auto vptr(const ArgType& arg) const -> vptr_type;
2292 
2293     template<typename MethodArgList, typename ArgType, typename... MoreArgTypes>
2294     auto resolve_uni(const ArgType& arg, const MoreArgTypes&... more_args) const
2295         -> detail::word;
2296 
2297     template<typename MethodArgList, typename ArgType, typename... MoreArgTypes>
2298     auto resolve_multi_first(
2299         const ArgType& arg,
2300         const MoreArgTypes&... more_args) const -> detail::word;
2301 
2302     template<
2303         std::size_t VirtualArg, typename MethodArgList, typename ArgType,
2304         typename... MoreArgTypes>
2305     auto resolve_multi_next(
2306         vptr_type dispatch, const ArgType& arg,
2307         const MoreArgTypes&... more_args) const -> detail::word;
2308 
2309     template<typename... ArgType>
2310     FunctionPointer resolve(const ArgType&... args) const;
2311 
2312     template<auto, typename>
2313     struct thunk;
2314 
2315     template<auto, typename>
2316     struct thunk;
2317 
2318     method();
2319     method(const method&) = delete;
2320     method(method&&) = delete;
2321     ~method();
2322 
2323     void resolve(); // virtual if Registry contains has_deferred_static_rtti
2324 
2325     static BOOST_NORETURN auto fn_not_implemented(
2326         detail::remove_virtual_<Parameters>... args) -> ReturnType;
2327     static BOOST_NORETURN auto
2328     fn_ambiguous(detail::remove_virtual_<Parameters>... args) -> ReturnType;
2329 
2330     template<
2331         auto Overrider, typename OverriderReturn,
2332         typename... OverriderParameters>
2333     struct thunk<Overrider, OverriderReturn (*)(OverriderParameters...)> {
2334         static auto
2335         fn(detail::remove_virtual_<Parameters>... arg) -> ReturnType;
2336         using OverriderVirtualParameters = detail::overrider_virtual_types<
2337             DeclaredParameters, mp11::mp_list<OverriderParameters...>,
2338             Registry>;
2339     };
2340 
2341     template<auto Function, typename FnReturnType>
2342     struct override_impl
2343         : std::conditional_t<
2344               Registry::has_deferred_static_rtti,
2345               detail::deferred_overrider_info, detail::overrider_info> {
2346         explicit override_impl(FunctionPointer* next = nullptr);
2347         void resolve_type_ids();
2348 
2349         static type_id vp_type_ids[Arity];
2350     };
2351 
2352     template<auto Function, typename FunctionType>
2353     struct override_aux;
2354 
2355     template<auto Function, typename FnReturnType, typename... FnParameters>
2356     struct override_aux<Function, FnReturnType (*)(FnParameters...)> {
2357         override_aux() {
2358             (void)&impl;
2359         }
2360 
2361         static override_impl<Function, FnReturnType> impl;
2362     };
2363 };
2364 
2365 template<
2366     typename Id, typename... Parameters, typename ReturnType, class Registry>
2367 method<Id, ReturnType(Parameters...), Registry>
2368     method<Id, ReturnType(Parameters...), Registry>::fn;
2369 
2370 template<
2371     typename Id, typename... Parameters, typename ReturnType, class Registry>
2372 template<auto Fn>
2373 typename method<Id, ReturnType(Parameters...), Registry>::FunctionPointer
2374     method<Id, ReturnType(Parameters...), Registry>::next;
2375 
2376 template<
2377     typename Id, typename... Parameters, typename ReturnType, class Registry>
2378 template<auto Function, typename FnReturnType>
2379 type_id method<Id, ReturnType(Parameters...), Registry>::override_impl<
2380     Function, FnReturnType>::vp_type_ids[Arity];
2381 
2382 template<
2383     typename Id, typename... Parameters, typename ReturnType, class Registry>
2384 template<auto Function, typename FnReturnType, typename... FnParameters>
2385 typename method<Id, ReturnType(Parameters...), Registry>::
2386     template override_impl<Function, FnReturnType>
2387         method<Id, ReturnType(Parameters...), Registry>::override_aux<
2388             Function, FnReturnType (*)(FnParameters...)>::impl;
2389 
2390 template<
2391     typename Id, typename... Parameters, typename ReturnType, class Registry>
2392 method<Id, ReturnType(Parameters...), Registry>::method() {
2393     using namespace policies;
2394 
2395     this->slots_strides_ptr = slots_strides;
2396 
2397     if constexpr (!Registry::has_deferred_static_rtti) {
2398         resolve_type_ids();
2399     }
2400 
2401     this->vp_begin = vp_type_ids;
2402     this->vp_end = vp_type_ids + Arity;
2403     this->not_implemented = reinterpret_cast<void (*)()>(fn_not_implemented);
2404     this->ambiguous = reinterpret_cast<void (*)()>(fn_ambiguous);
2405 
2406     Registry::methods.push_back(*this);
2407 }
2408 
2409 template<
2410     typename Id, typename... Parameters, typename ReturnType, class Registry>
2411 void method<Id, ReturnType(Parameters...), Registry>::resolve_type_ids() {
2412     using namespace detail;
2413     this->method_type_id = rtti::template static_type<method>();
2414     this->return_type_id =
2415         rtti::template static_type<virtual_type<ReturnType, Registry>>();
2416     init_type_ids<
2417         Registry,
2418         mp11::mp_transform_q<
2419             mp11::mp_bind_back<virtual_type, Registry>,
2420             VirtualParameters>>::fn(this->vp_type_ids);
2421 }
2422 
2423 template<
2424     typename Id, typename... Parameters, typename ReturnType, class Registry>
2425 method<Id, ReturnType(Parameters...), Registry>::~method() {
2426     Registry::methods.remove(*this);
2427 }
2428 
2429 // -----------------------------------------------------------------------------
2430 // method dispatch
2431 
2432 template<
2433     typename Id, typename... Parameters, typename ReturnType, class Registry>
2434 BOOST_FORCEINLINE auto
2435 method<Id, ReturnType(Parameters...), Registry>::operator()(
2436     typename BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
2437         StripVirtualDecorator<Parameters>::type... args) const -> ReturnType {
2438     using namespace detail;
2439     auto pf = resolve(parameter_traits<Parameters, Registry>::peek(args)...);
2440 
2441     return pf(std::forward<typename StripVirtualDecorator<Parameters>::type>(
2442         args)...);
2443 }
2444 
2445 template<
2446     typename Id, typename... Parameters, typename ReturnType, class Registry>
2447 template<typename... ArgType>
2448 BOOST_FORCEINLINE
2449     typename method<Id, ReturnType(Parameters...), Registry>::FunctionPointer
2450     method<Id, ReturnType(Parameters...), Registry>::resolve(
2451         const ArgType&... args) const {
2452     using namespace detail;
2453 
2454     Registry::require_initialized();
2455 
2456     void (*pf)();
2457 
2458     if constexpr (Arity == 1) {
2459         pf = resolve_uni<mp11::mp_list<Parameters...>, ArgType...>(args...).pf;
2460     } else {
2461         pf = resolve_multi_first<mp11::mp_list<Parameters...>, ArgType...>(
2462                  args...)
2463                  .pf;
2464     }
2465 
2466     return reinterpret_cast<FunctionPointer>(pf);
2467 }
2468 
2469 template<
2470     typename Id, typename... Parameters, typename ReturnType, class Registry>
2471 template<typename ArgType>
2472 BOOST_FORCEINLINE auto method<Id, ReturnType(Parameters...), Registry>::vptr(
2473     const ArgType& arg) const -> vptr_type {
2474     if constexpr (detail::is_virtual_ptr<ArgType>) {
2475         return arg.vptr();
2476     } else {
2477         return detail::acquire_vptr<Registry>(arg);
2478     }
2479 }
2480 
2481 template<
2482     typename Id, typename... Parameters, typename ReturnType, class Registry>
2483 template<typename MethodArgList, typename ArgType, typename... MoreArgTypes>
2484 BOOST_FORCEINLINE auto
2485 method<Id, ReturnType(Parameters...), Registry>::resolve_uni(
2486     const ArgType& arg,
2487     const MoreArgTypes&... more_args) const -> detail::word {
2488 
2489     using namespace detail;
2490     using namespace policies;
2491     using namespace boost::mp11;
2492 
2493     if constexpr (is_virtual<mp_first<MethodArgList>>::value) {
2494         vptr_type vtbl = vptr<ArgType>(arg);
2495         return vtbl[this->slots_strides[0]];
2496     } else {
2497         return resolve_uni<mp_rest<MethodArgList>>(more_args...);
2498     }
2499 }
2500 
2501 template<
2502     typename Id, typename... Parameters, typename ReturnType, class Registry>
2503 template<typename MethodArgList, typename ArgType, typename... MoreArgTypes>
2504 BOOST_FORCEINLINE auto
2505 method<Id, ReturnType(Parameters...), Registry>::resolve_multi_first(
2506     const ArgType& arg,
2507     const MoreArgTypes&... more_args) const -> detail::word {
2508 
2509     using namespace detail;
2510     using namespace boost::mp11;
2511 
2512     if constexpr (is_virtual<mp_first<MethodArgList>>::value) {
2513         vptr_type vtbl = vptr<ArgType>(arg);
2514         std::size_t slot = this->slots_strides[0];
2515 
2516         // The first virtual parameter is special.  Since its stride is
2517         // 1, there is no need to store it. Also, the method table
2518         // contains a pointer into the multi-dimensional dispatch table,
2519         // already resolved to the appropriate group.
2520         auto dispatch = vtbl[slot].pw;
2521         return resolve_multi_next<1, mp_rest<MethodArgList>, MoreArgTypes...>(
2522             dispatch, more_args...);
2523     } else {
2524         return resolve_multi_first<mp_rest<MethodArgList>, MoreArgTypes...>(
2525             more_args...);
2526     }
2527 }
2528 
2529 template<
2530     typename Id, typename... Parameters, typename ReturnType, class Registry>
2531 template<
2532     std::size_t VirtualArg, typename MethodArgList, typename ArgType,
2533     typename... MoreArgTypes>
2534 BOOST_FORCEINLINE auto
2535 method<Id, ReturnType(Parameters...), Registry>::resolve_multi_next(
2536     vptr_type dispatch, const ArgType& arg,
2537     const MoreArgTypes&... more_args) const -> detail::word {
2538 
2539     using namespace detail;
2540     using namespace boost::mp11;
2541 
2542     if constexpr (is_virtual<mp_first<MethodArgList>>::value) {
2543         vptr_type vtbl = vptr<ArgType>(arg);
2544         std::size_t slot = this->slots_strides[VirtualArg];
2545         std::size_t stride = this->slots_strides[Arity + VirtualArg - 1];
2546         dispatch = dispatch + vtbl[slot].i * stride;
2547     }
2548 
2549     if constexpr (VirtualArg + 1 == Arity) {
2550         return *dispatch;
2551     } else {
2552         return resolve_multi_next<
2553             VirtualArg + 1, mp_rest<MethodArgList>, MoreArgTypes...>(
2554             dispatch, more_args...);
2555     }
2556 }
2557 
2558 // -----------------------------------------------------------------------------
2559 // Error handling
2560 
2561 template<
2562     typename Id, typename... Parameters, typename ReturnType, class Registry>
2563 template<auto Fn>
2564 inline auto
2565 method<Id, ReturnType(Parameters...), Registry>::has_next() -> bool {
2566     if (next<Fn> == fn_not_implemented) {
2567         return false;
2568     }
2569 
2570     if (next<Fn> == fn_ambiguous) {
2571         return false;
2572     }
2573 
2574     return true;
2575 }
2576 
2577 template<
2578     typename Id, typename... Parameters, typename ReturnType, class Registry>
2579 BOOST_NORETURN auto
2580 method<Id, ReturnType(Parameters...), Registry>::fn_not_implemented(
2581     detail::remove_virtual_<Parameters>... args) -> ReturnType {
2582     using namespace policies;
2583 
2584     if constexpr (Registry::has_error_handler) {
2585         no_overrider error;
2586         detail::init_bad_call<method, rtti, 0u>::fn(
2587             error,
2588             detail::parameter_traits<Parameters, Registry>::peek(args)...);
2589         Registry::error_handler::error(error);
2590     }
2591 
2592     abort(); // in case user handler "forgets" to abort
2593 }
2594 
2595 template<
2596     typename Id, typename... Parameters, typename ReturnType, class Registry>
2597 BOOST_NORETURN auto
2598 method<Id, ReturnType(Parameters...), Registry>::fn_ambiguous(
2599     detail::remove_virtual_<Parameters>... args) -> ReturnType {
2600     using namespace policies;
2601 
2602     if constexpr (Registry::has_error_handler) {
2603         ambiguous_call error;
2604         detail::init_bad_call<method, rtti, 0u>::fn(
2605             error,
2606             detail::parameter_traits<Parameters, Registry>::peek(args)...);
2607         Registry::error_handler::error(error);
2608     }
2609 
2610     abort(); // in case user handler "forgets" to abort
2611 }
2612 
2613 // -----------------------------------------------------------------------------
2614 // overriders
2615 
2616 namespace detail {
2617 
2618 template<typename T, typename U>
2619 struct same_reference_category {
2620     static constexpr bool value = (std::is_lvalue_reference<T>::value ==
2621                                    std::is_lvalue_reference<U>::value) &&
2622         (std::is_rvalue_reference<T>::value ==
2623          std::is_rvalue_reference<U>::value);
2624 };
2625 template<class T1, class T2, typename = void>
2626 struct validate_overrider_parameter : std::false_type {
2627     static_assert(
2628         false_t<T1, T2>, "non-virtual parameter types must match exactly");
2629 };
2630 
2631 template<class T1, class T2>
2632 struct validate_overrider_parameter<
2633     T1, T2,
2634     std::enable_if_t<
2635         is_virtual_ptr<T1> && is_virtual_ptr<T2> &&
2636         !same_reference_category<T1, T2>::value>> : std::false_type {
2637     static_assert(
2638         false_t<T1, T2>, "different virtual_ptr<> reference categories");
2639 };
2640 
2641 template<class T1, class T2>
2642 struct validate_overrider_parameter<
2643     T1, T2, std::enable_if_t<is_virtual_ptr<T1> && !is_virtual_ptr<T2>>>
2644     : std::false_type {
2645     static_assert(
2646         false_t<T1, T2>,
2647         "virtual_ptr<> is required in overrider in same position as in "
2648         "method");
2649 };
2650 
2651 template<class T>
2652 struct validate_overrider_parameter<T, T, void> : std::true_type {};
2653 
2654 template<class T1, class T2>
2655 struct validate_overrider_parameter<virtual_<T1>, T2, void> : std::true_type {};
2656 
2657 template<class T1, class T2>
2658 struct validate_overrider_parameter<virtual_<T1>, virtual_<T2>, void>
2659     : std::false_type {
2660     static_assert(false_t<T1, T2>, "virtual_<> is not allowed in overriders");
2661 };
2662 
2663 template<class T, class R>
2664 struct validate_overrider_parameter<virtual_ptr<T, R>, virtual_ptr<T, R>, void>
2665     : std::true_type {};
2666 
2667 template<class T1, class R, class T2, class R2>
2668 struct validate_overrider_parameter<
2669     virtual_ptr<T1, R>, virtual_ptr<T2, R2>, void> : std::true_type {
2670     static_assert(std::is_same_v<R, R2>, "registry mismatch");
2671     using C1 = virtual_type<virtual_ptr<T1, R>, R>;
2672     using C2 = virtual_type<virtual_ptr<T2, R>, R>;
2673     static_assert(
2674         std::is_base_of_v<C1, C2> &&
2675             std::is_convertible_v<virtual_ptr<T2, R>, virtual_ptr<T1, R>>,
2676         "method parameter must be an unambiguous accessible base "
2677         "of corresponding overrider parameter");
2678 };
2679 
2680 template<class T1, class R, class T2, class R2>
2681 struct validate_overrider_parameter<
2682     const virtual_ptr<T1, R>&, const virtual_ptr<T2, R2>&, void>
2683     : std::true_type {
2684     static_assert(std::is_same_v<R, R2>, "registry mismatch");
2685     using C1 = virtual_type<const virtual_ptr<T1, R>&, R>;
2686     using C2 = virtual_type<const virtual_ptr<T2, R>&, R>;
2687     static_assert(
2688         std::is_base_of_v<C1, C2> &&
2689             std::is_convertible_v<virtual_ptr<T2, R>, virtual_ptr<T1, R>>,
2690         "method parameter must be an unambiguous accessible base "
2691         "of corresponding overrider parameter");
2692 };
2693 
2694 template<class T1, class R, class T2, class R2>
2695 struct validate_overrider_parameter<
2696     virtual_ptr<T1, R>&&, virtual_ptr<T2, R2>&&, void> : std::true_type {
2697     static_assert(std::is_same_v<R, R2>, "registry mismatch");
2698     using C1 = virtual_type<virtual_ptr<T1, R>&&, R>;
2699     using C2 = virtual_type<virtual_ptr<T2, R>&&, R>;
2700     static_assert(
2701         std::is_base_of_v<C1, C2> &&
2702             std::is_convertible_v<virtual_ptr<T2, R>, virtual_ptr<T1, R>>,
2703         "method parameter must be an unambiguous accessible base "
2704         "of corresponding overrider parameter");
2705 };
2706 
2707 } // namespace detail
2708 
2709 template<
2710     typename Id, typename... Parameters, typename ReturnType, class Registry>
2711 template<
2712     auto Overrider, typename OverriderReturn, typename... OverriderParameters>
2713 auto method<Id, ReturnType(Parameters...), Registry>::
2714     thunk<Overrider, OverriderReturn (*)(OverriderParameters...)>::fn(
2715         detail::remove_virtual_<Parameters>... arg) -> ReturnType {
2716     using namespace detail;
2717     static_assert(
2718         (validate_overrider_parameter<Parameters, OverriderParameters>::value &&
2719          ...),
2720         "virtual_ptr category mismatch");
2721     return Overrider(
2722         detail::parameter_traits<Parameters, Registry>::template cast<
2723             OverriderParameters>(
2724             std::forward<detail::remove_virtual_<Parameters>>(arg))...);
2725 }
2726 
2727 template<
2728     typename Id, typename... Parameters, typename ReturnType, class Registry>
2729 template<auto Function, typename FnReturnType>
2730 method<Id, ReturnType(Parameters...), Registry>::override_impl<
2731     Function, FnReturnType>::override_impl(FunctionPointer* p_next) {
2732     using namespace detail;
2733 
2734     // static variable this->method below is zero-initialized but gcc and clang
2735     // don't always see that.
2736 
2737 #ifdef BOOST_CLANG
2738 #pragma clang diagnostic push
2739 #pragma clang diagnostic ignored "-Wuninitialized"
2740 #endif
2741 
2742 #ifdef BOOST_GCC
2743 #pragma GCC diagnostic push
2744 #pragma GCC diagnostic ignored "-Wuninitialized"
2745 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
2746 #endif
2747 
2748     // zero-initalized static variable
2749     // coverity[uninit_use:FALSE]
2750     if (overrider_info::method) {
2751         BOOST_ASSERT(overrider_info::method == &fn);
2752         return;
2753     }
2754 
2755 #ifdef BOOST_CLANG
2756 #pragma clang diagnostic pop
2757 #endif
2758 
2759 #ifdef BOOST_GCC
2760 #pragma GCC diagnostic pop
2761 #endif
2762 
2763     overrider_info::method = &fn;
2764 
2765     if constexpr (!Registry::has_deferred_static_rtti) {
2766         resolve_type_ids();
2767     }
2768 
2769     this->next = reinterpret_cast<void (**)()>(
2770         p_next ? p_next : &method::next<Function>);
2771 
2772     using Thunk = thunk<Function, decltype(Function)>;
2773     this->pf = reinterpret_cast<void (*)()>(Thunk::fn);
2774 
2775     this->vp_begin = vp_type_ids;
2776     this->vp_end = vp_type_ids + Arity;
2777 
2778     fn.overriders.push_back(*this);
2779 }
2780 
2781 template<
2782     typename Id, typename... Parameters, typename ReturnType, class Registry>
2783 template<auto Function, typename FnReturnType>
2784 void method<Id, ReturnType(Parameters...), Registry>::override_impl<
2785     Function, FnReturnType>::resolve_type_ids() {
2786     using namespace detail;
2787 
2788     this->return_type = Registry::rtti::template static_type<
2789         virtual_type<FnReturnType, Registry>>();
2790     this->type = Registry::rtti::template static_type<decltype(Function)>();
2791     using Thunk = thunk<Function, decltype(Function)>;
2792     detail::
2793         init_type_ids<Registry, typename Thunk::OverriderVirtualParameters>::fn(
2794             this->vp_type_ids);
2795 }
2796 
2797 //! Aliases for the most frequently used types in the library.
2798 namespace aliases {
2799 
2800 using boost::openmethod::final_virtual_ptr;
2801 using boost::openmethod::virtual_;
2802 using boost::openmethod::virtual_ptr;
2803 
2804 } // namespace aliases
2805 
2806 // ==============================================================================
2807 // Exposition only
2808 
2809 #ifdef __MRDOCS__
2810 
2811 //! Blueprint for a specialization of @ref virtual_traits (exposition only).
2812 //!
2813 //! Specializations of @ref virtual_traits must implement the members listed
2814 //! here.
2815 //!
2816 //! @tparam T The type of a virtual parameter of a method.
2817 //! @tparam Registry A @ref registry.
2818 template<typename T, class Registry>
2819 struct VirtualTraits {
2820     //! Class to use for dispatch.
2821     //!
2822     //! Aliases to the class to be considered during method dispatch to determine
2823     //! which overrider to select, and which type_id to use for error reporting.
2824     //! `virtual_traits<T>::virtual_type` aliases to `Class` if `T` is `Class&`,
2825     //! `const Class&`, `Class*`, `const Class*`, `virtual_ptr<Class>`,
2826     //! `virtual_ptr<const Class>`, `std::shared_ptr<Class>`,
2827     //! `std::shared_ptr<const Class>`, `virtual_ptr<std::shared_ptr<Class>>`,
2828     //! etc.
2829     //!
2830     //! @par Requirements
2831     //!
2832     //! `virtual_type` must be an alias to an *unadorned* *class* type, *not*
2833     //! cv-qualified.
2834     using virtual_type = detail::unspecified;
2835 
2836     //! Returns a reference to the object to use for dispatch.
2837     //!
2838     //! Return a reference to the object to use for dispatch. `arg` may not be
2839     //! copied, moved or altered in any way.
2840     //!
2841     //! @param arg An argument passed to the method call.
2842     //! @return A reference to an object.
2843     static auto peek(T arg) -> const virtual_type&;
2844 
2845     //! Casts a virtual argument.
2846     //!
2847     //! Casts a virtual argument to the type expected by the overrider.
2848     //!
2849     //! @tparam T The type of a virtual parameter of a method.
2850     //! @tparam U The type of a virtual parameter of an overrider.
2851     //! @param arg The argument passed to a method call.
2852     //! @return A reference to the argument, cast to `U`.
2853     template<typename U>
2854     static auto cast(T arg) -> U;
2855 
2856     //! Rebind to a another class (smart pointers only).
2857     //!
2858     //! If `T` is a smart pointer, `rebind<U>` is the same kind of smart
2859     //! pointer, but pointing to a `U`.
2860     //!
2861     //! @note `rebind` must be implemented @em only for smart pointer classes
2862     //! that can be used as object pointers by @ref virtual_ptr in place of
2863     //! plain pointers.
2864     //!
2865     //! @tparam U The new element type.
2866     template<class U>
2867     using rebind = detail::unspecified;
2868 };
2869 
2870 #endif
2871 
2872 } // namespace boost::openmethod
2873 
2874 #ifdef _MSC_VER
2875 #pragma warning(pop)
2876 #endif
2877 
2878 #endif