Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions include/boost/openmethod/core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1003,12 +1003,19 @@ struct is_virtual_ptr_aux<const virtual_ptr<Class, Registry, void>&> :
template<typename T>
constexpr bool is_virtual_ptr = detail::is_virtual_ptr_aux<T>::value;

// Whether `boost_openmethod_vptr`, the customization point found by ADL, yields
// a v-table pointer for `Class` in `Registry`. The class provides it, as
// `inplace_vptr_base` does; the catch-all `boost_openmethod_vptr(...)` makes
// the question safe to ask of any class.
template<class Class, class Registry>
constexpr bool has_vptr_fn = std::is_same_v<
constexpr bool has_adl_vptr = std::is_same_v<
decltype(boost_openmethod_vptr(
std::declval<const Class&>(), std::declval<Registry*>())),
vptr_type>;

// `has_vptr<Traits, Arg>`: whether `Traits::vptr(arg)` exists. That is how a
// `virtual_traits` specialization yields a v-table pointer, for a type that
// cannot carry an ADL overload of its own, such as `std::any`.
BOOST_OPENMETHOD_DETAIL_HAS_STATIC_FN(vptr);

template<class Registry, class ArgType>
Expand All @@ -1018,7 +1025,7 @@ decltype(auto) acquire_vptr(const ArgType& arg) {
// to the v-table pointer. The hook also returns the vptr by value,
// which indirect registries cannot store (see box_vptr).
static_assert(
!has_vptr_fn<ArgType, Registry>,
!has_adl_vptr<ArgType, Registry>,
"do not wrap an object that has a boost_openmethod_vptr overload "
"in a virtual_ptr; call methods directly on the object");

Expand Down Expand Up @@ -2326,7 +2333,7 @@ struct parameter_traits<const virtual_ptr<Class, Registry, void>&, Registry> :
// indentation, and because each route is worth naming.
template<typename T, class Registry>
constexpr bool has_vptr_source =
has_vptr_fn<virtual_type<T, Registry>, Registry> ||
has_adl_vptr<virtual_type<T, Registry>, Registry> ||
has_vptr<
virtual_traits<T, Registry>,
decltype(virtual_traits<T, Registry>::peek(std::declval<T>()))> ||
Expand Down Expand Up @@ -2946,7 +2953,7 @@ BOOST_FORCEINLINE auto method<Id, ReturnType(Parameters...), Registry>::vptr(
} else {
decltype(auto) obj = virtual_traits<MethodArg, Registry>::peek(arg);

if constexpr (detail::has_vptr_fn<decltype(obj), Registry>) {
if constexpr (detail::has_adl_vptr<decltype(obj), Registry>) {
return boost_openmethod_vptr(obj, static_cast<Registry*>(nullptr));
} else if constexpr (
detail::has_vptr<
Expand Down
6 changes: 3 additions & 3 deletions test/test_core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ struct Animal {
friend auto boost_openmethod_vptr(const Animal&, void*) -> vptr_type;
};

static_assert(detail::has_vptr_fn<Animal, default_registry>);
static_assert(detail::has_adl_vptr<Animal, default_registry>);

} // namespace TEST_NS

Expand All @@ -274,8 +274,8 @@ struct Animal {
-> vptr_type;
};

static_assert(detail::has_vptr_fn<Animal, test_registry>);
static_assert(!detail::has_vptr_fn<Animal, default_registry>);
static_assert(detail::has_adl_vptr<Animal, test_registry>);
static_assert(!detail::has_adl_vptr<Animal, default_registry>);

// The hook serves dispatch (method::vptr), not virtual_ptr: acquire_vptr
// rejects classes with a boost_openmethod_vptr overload at compile time -
Expand Down
8 changes: 4 additions & 4 deletions test/test_dispatch_type_erasure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,8 +311,8 @@ using dispatchable_ref = te::any<Dispatchable, te::_self&>;

// the intrinsic hook is found for every any, so dispatch prefers it
// over the vptr policy's hash lookup
static_assert(detail::has_vptr_fn<dispatchable, default_registry>);
static_assert(detail::has_vptr_fn<dispatchable_ref, default_registry>);
static_assert(detail::has_adl_vptr<dispatchable, default_registry>);
static_assert(detail::has_adl_vptr<dispatchable_ref, default_registry>);

// `Dog` is registered both by the `name` overrider below and by binding
// (class dedup)
Expand Down Expand Up @@ -377,8 +377,8 @@ using dispatchable = te::any<Dispatchable>;
// The hook is keyed on the registry the concept names: it is found for
// `indirect_registry`, and for no other - a mismatch would fall back on the
// vptr policy's hash lookup, silently losing the constant-time property.
static_assert(detail::has_vptr_fn<dispatchable, indirect_registry>);
static_assert(!detail::has_vptr_fn<dispatchable, default_registry>);
static_assert(detail::has_adl_vptr<dispatchable, indirect_registry>);
static_assert(!detail::has_adl_vptr<dispatchable, default_registry>);

using name_method = method<
struct name_id, std::string(virtual_<const dispatchable&>),
Expand Down
Loading