mirror of
https://github.com/boostorg/openmethod.git
synced 2026-01-19 04:22:12 +00:00
better compile-time error messages
This commit is contained in:
@@ -480,6 +480,10 @@ namespace detail {
|
||||
template<class Class, class Registry>
|
||||
struct is_virtual<virtual_ptr<Class, Registry, void>> : std::true_type {};
|
||||
|
||||
template<class Class, class Registry>
|
||||
struct is_virtual<virtual_ptr<Class, Registry, void>&> : std::true_type {
|
||||
};
|
||||
|
||||
template<class Class, class Registry>
|
||||
struct is_virtual<const virtual_ptr<Class, Registry, void>&> : std::true_type {
|
||||
};
|
||||
@@ -1920,27 +1924,6 @@ struct has_static_offsets<
|
||||
Method, std::void_t<decltype(static_offsets<Method>::slots)>>
|
||||
: std::true_type {};
|
||||
|
||||
template<class Registry, class Parameter>
|
||||
struct using_same_registry : std::true_type {};
|
||||
|
||||
template<class Registry, typename Type, class OtherRegistry>
|
||||
struct using_same_registry<Registry, virtual_ptr<Type, OtherRegistry>>
|
||||
: std::is_same<Registry, OtherRegistry> {};
|
||||
|
||||
template<class Registry, typename Type, class OtherRegistry>
|
||||
struct using_same_registry<Registry, const virtual_ptr<Type, OtherRegistry>&>
|
||||
: std::is_same<Registry, OtherRegistry> {};
|
||||
|
||||
template<typename, class>
|
||||
struct valid_method_parameter : std::true_type {};
|
||||
|
||||
template<typename T, class Registry>
|
||||
struct valid_method_parameter<virtual_<T>, Registry>
|
||||
: std::bool_constant<
|
||||
has_vptr_fn<virtual_type<T, Registry>, Registry> ||
|
||||
Registry::rtti::template is_polymorphic<virtual_type<T, Registry>>> {
|
||||
};
|
||||
|
||||
template<class Registry>
|
||||
using method_base = std::conditional_t<
|
||||
Registry::has_deferred_static_rtti, deferred_method_info, method_info>;
|
||||
@@ -1968,6 +1951,40 @@ template<class Class, class Registry>
|
||||
struct parameter_traits<const virtual_ptr<Class, Registry, void>&, Registry>
|
||||
: virtual_traits<const virtual_ptr<Class, Registry, void>&, Registry> {};
|
||||
|
||||
template<typename...>
|
||||
constexpr bool false_t = false; // workaround before CWG2518/P2593R1
|
||||
|
||||
template<typename T, class Registry, typename = void>
|
||||
struct check_method_parameter : std::true_type {};
|
||||
|
||||
template<typename T, class Registry, typename U>
|
||||
struct check_method_parameter<virtual_<T>, Registry, U> : std::false_type {
|
||||
static_assert(false_t<T>, "virtual_traits not specialized for type");
|
||||
};
|
||||
|
||||
template<typename T, class Registry>
|
||||
struct check_method_parameter<
|
||||
virtual_<T>, Registry,
|
||||
std::void_t<typename virtual_traits<T, Registry>::virtual_type>>
|
||||
: std::bool_constant<
|
||||
has_vptr_fn<virtual_type<T, Registry>, Registry> ||
|
||||
Registry::rtti::template is_polymorphic<virtual_type<T, Registry>>> {
|
||||
static_assert(
|
||||
check_method_parameter::value,
|
||||
"virtual_<> parameter is not a polymorphic class and no "
|
||||
"boost_openmethod_vptr is applicable");
|
||||
};
|
||||
|
||||
template<class Class, class Registry>
|
||||
struct check_method_parameter<virtual_ptr<Class, Registry>, Registry, void>
|
||||
: std::true_type {};
|
||||
|
||||
template<class Class, class Registry, class MethodRegistry>
|
||||
struct check_method_parameter<
|
||||
virtual_ptr<Class, Registry>, MethodRegistry, void> : std::false_type {
|
||||
static_assert(
|
||||
false_t<Class, Registry, MethodRegistry>, "registry mismatch");
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
//! Implement a method
|
||||
@@ -2182,14 +2199,9 @@ class method<Id, ReturnType(Parameters...), Registry>
|
||||
mp11::mp_list<Parameters...>, detail::is_virtual>::value;
|
||||
|
||||
// sanity checks
|
||||
static_assert(
|
||||
(detail::check_method_parameter<Parameters, Registry>::value && ...));
|
||||
static_assert(Arity > 0, "method has no virtual parameters");
|
||||
static_assert(
|
||||
(... && detail::using_same_registry<Registry, Parameters>::value),
|
||||
"method and parameters use different registries");
|
||||
static_assert(
|
||||
(... && detail::valid_method_parameter<Parameters, Registry>::value),
|
||||
"virtual_<> parameter is not polymorphic and no boost_openmethod_vptr "
|
||||
"function is available");
|
||||
|
||||
type_id vp_type_ids[Arity];
|
||||
|
||||
@@ -2599,38 +2611,74 @@ method<Id, ReturnType(Parameters...), Registry>::fn_ambiguous(
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// thunk
|
||||
// overriders
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class T, class U>
|
||||
struct compatible_parameters : std::is_same<T, U> {
|
||||
template<typename T, typename U>
|
||||
struct same_reference_category {
|
||||
static constexpr bool value = (std::is_lvalue_reference<T>::value ==
|
||||
std::is_lvalue_reference<U>::value) &&
|
||||
(std::is_rvalue_reference<T>::value ==
|
||||
std::is_rvalue_reference<U>::value);
|
||||
};
|
||||
template<class T1, class T2, typename = void>
|
||||
struct check_overrider_parameter : std::false_type {
|
||||
static_assert(
|
||||
compatible_parameters::value,
|
||||
"non-virtual parameters must have the same type");
|
||||
false_t<T1, T2>, "non-virtual parameter types must match exactly");
|
||||
};
|
||||
|
||||
template<class T, class U>
|
||||
struct compatible_parameters<virtual_<T>, U> : std::true_type {};
|
||||
|
||||
template<class T, class U>
|
||||
struct compatible_parameters<virtual_<T>, virtual_<U>> : std::false_type {
|
||||
template<class T1, class T2>
|
||||
struct check_overrider_parameter<
|
||||
T1, T2,
|
||||
std::enable_if_t<
|
||||
is_virtual_ptr<T1> && is_virtual_ptr<T2> &&
|
||||
!same_reference_category<T1, T2>::value>> : std::false_type {
|
||||
static_assert(
|
||||
false, "virtual_<> is not allowed in overrider parameter lists");
|
||||
false_t<T1, T2>, "different virtual_ptr<> reference categories");
|
||||
};
|
||||
|
||||
template<class T, class U, class Registry>
|
||||
struct compatible_parameters<virtual_ptr<T, Registry>, virtual_ptr<U, Registry>>
|
||||
template<class T1, class T2>
|
||||
struct check_overrider_parameter<
|
||||
T1, T2, std::enable_if_t<is_virtual_ptr<T1> && !is_virtual_ptr<T2>>>
|
||||
: std::false_type {
|
||||
static_assert(
|
||||
false_t<T1, T2>,
|
||||
"virtual_ptr<> is required in overrider in same position as in "
|
||||
"method");
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct check_overrider_parameter<T, T, void> : std::true_type {};
|
||||
|
||||
template<class T1, class T2>
|
||||
struct check_overrider_parameter<virtual_<T1>, T2, void> : std::true_type {};
|
||||
|
||||
template<class T1, class T2>
|
||||
struct check_overrider_parameter<virtual_<T1>, virtual_<T2>, void>
|
||||
: std::false_type {
|
||||
static_assert(false_t<T1, T2>, "virtual_<> is not allowed in overriders");
|
||||
};
|
||||
|
||||
template<class T, class R>
|
||||
struct check_overrider_parameter<virtual_ptr<T, R>, virtual_ptr<T, R>, void>
|
||||
: std::true_type {};
|
||||
|
||||
template<class T, class U, class Registry>
|
||||
struct compatible_parameters<
|
||||
const virtual_ptr<T, Registry>&, const virtual_ptr<U, Registry>&>
|
||||
: std::true_type {};
|
||||
template<class T1, class R1, class T2, class R2>
|
||||
struct check_overrider_parameter<virtual_ptr<T1, R1>, virtual_ptr<T2, R2>, void>
|
||||
: std::is_same<R1, R2> {
|
||||
static_assert(check_overrider_parameter::value, "registry mismatch");
|
||||
};
|
||||
|
||||
template<class T, class U, class Registry>
|
||||
struct compatible_parameters<
|
||||
virtual_ptr<T, Registry>&&, virtual_ptr<U, Registry>&&> : std::true_type {};
|
||||
template<class T1, class R1, class T2, class R2>
|
||||
struct check_overrider_parameter<
|
||||
const virtual_ptr<T1, R1>&, const virtual_ptr<T2, R2>&, void>
|
||||
: check_overrider_parameter<virtual_ptr<T1, R1>, virtual_ptr<T2, R2>> {};
|
||||
|
||||
template<class T1, class R1, class T2, class R2>
|
||||
struct check_overrider_parameter<
|
||||
virtual_ptr<T1, R1>&&, virtual_ptr<T2, R2>&&, void>
|
||||
: check_overrider_parameter<virtual_ptr<T1, R1>, virtual_ptr<T2, R2>> {};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -2643,7 +2691,8 @@ auto method<Id, ReturnType(Parameters...), Registry>::
|
||||
detail::remove_virtual_<Parameters>... arg) -> ReturnType {
|
||||
using namespace detail;
|
||||
static_assert(
|
||||
(compatible_parameters<Parameters, OverriderParameters>::value && ...),
|
||||
(check_overrider_parameter<Parameters, OverriderParameters>::value &&
|
||||
...),
|
||||
"virtual_ptr category mismatch");
|
||||
return Overrider(
|
||||
detail::parameter_traits<Parameters, Registry>::template cast<
|
||||
@@ -2651,9 +2700,6 @@ auto method<Id, ReturnType(Parameters...), Registry>::
|
||||
std::forward<detail::remove_virtual_<Parameters>>(arg))...);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// overriders
|
||||
|
||||
template<
|
||||
typename Id, typename... Parameters, typename ReturnType, class Registry>
|
||||
template<auto Function, typename FnReturnType>
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace detail {
|
||||
|
||||
template<class T>
|
||||
struct shared_ptr_cast_traits {
|
||||
static_assert(false, "invalid cast");
|
||||
static_assert(false_t<T>, "cast only allowed to a shared_ptr");
|
||||
};
|
||||
|
||||
template<class T>
|
||||
@@ -32,6 +32,23 @@ struct shared_ptr_cast_traits<std::shared_ptr<T>&&> {
|
||||
using virtual_type = T;
|
||||
};
|
||||
|
||||
template<typename T, class Registry>
|
||||
struct check_method_parameter<std::shared_ptr<T>&, Registry, void>
|
||||
: std::false_type {
|
||||
static_assert(
|
||||
false_t<T>,
|
||||
"std::shared_ptr cannot be passed by non-const lvalue reference");
|
||||
};
|
||||
|
||||
template<typename T, class Registry>
|
||||
struct check_method_parameter<
|
||||
virtual_ptr<std::shared_ptr<T>, Registry>&, Registry, void>
|
||||
: std::false_type {
|
||||
static_assert(
|
||||
false_t<T>,
|
||||
"std::shared_ptr cannot be passed by non-const lvalue reference");
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
//! Specialize virtual_traits for std::shared_ptr by value.
|
||||
|
||||
@@ -28,17 +28,16 @@ struct virtual_traits<std::unique_ptr<Class>, Registry> {
|
||||
return *arg;
|
||||
}
|
||||
|
||||
//! Cast to another type.
|
||||
//! Cast to a type.
|
||||
//!
|
||||
//! Cast the object pointed to another type, using `static_cast` if
|
||||
//! possible, and `Registry::rtti::dynamic_cast_ref` otherwise. If the
|
||||
//! cast succeeds, return a `std::unique_ptr` to the object,
|
||||
//! transferring ownership to it.
|
||||
//! Cast a reference to the managed object, using `static_cast` if possible,
|
||||
//! and `Registry::rtti::dynamic_cast_ref` otherwise. If the cast succeeds,
|
||||
//! transfer ownership to a `std::unique_ptr` to the target type, and return
|
||||
//! it.
|
||||
//!
|
||||
//! @tparam Derived A lvalue reference type to a `std::unique_ptr`.
|
||||
//! @param obj A xvalue reference to a `unique_ptr<Class>`.
|
||||
//! @return A `std::unique_ptr` to the same object, cast to
|
||||
//! `Derived::element_type`.
|
||||
//! @tparam Derived A xvalue reference to a `std::unique_ptr`.
|
||||
//! @param obj A xvalue reference to a `std::unique_ptr`.
|
||||
//! @return A `std::unique_ptr<Derived::element_type>`.
|
||||
template<typename Derived>
|
||||
static auto cast(std::unique_ptr<Class>&& ptr) {
|
||||
if constexpr (detail::requires_dynamic_cast<Class&, Derived&>) {
|
||||
|
||||
17
test/compile_fail_non_polymorphic_virtual_parameter.cpp
Normal file
17
test/compile_fail_non_polymorphic_virtual_parameter.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) 2018-2025 Jean-Louis Leroy
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// See accompanying file LICENSE_1_0.txt
|
||||
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/openmethod.hpp>
|
||||
|
||||
using boost::openmethod::virtual_;
|
||||
|
||||
struct Cat {};
|
||||
|
||||
BOOST_OPENMETHOD(poke, (virtual_<Cat&>), void);
|
||||
|
||||
int main() {
|
||||
poke(Cat{});
|
||||
return 0;
|
||||
}
|
||||
@@ -7,5 +7,9 @@
|
||||
|
||||
struct Cat {};
|
||||
|
||||
Cat felix;
|
||||
boost::openmethod::virtual_ptr<Cat> p(felix);
|
||||
int main() {
|
||||
Cat felix;
|
||||
boost::openmethod::virtual_ptr<Cat> p(felix);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -7,6 +7,12 @@
|
||||
|
||||
using boost::openmethod::virtual_;
|
||||
|
||||
struct Cat {};
|
||||
struct Cat { virtual ~Cat() {} };
|
||||
|
||||
BOOST_OPENMETHOD(poke, (virtual_<Cat>), void);
|
||||
|
||||
int main() {
|
||||
Cat felix;
|
||||
poke(felix);
|
||||
return 0;
|
||||
}
|
||||
@@ -7,7 +7,13 @@
|
||||
|
||||
using namespace boost::openmethod;
|
||||
|
||||
struct Cat {};
|
||||
struct Cat { virtual ~Cat() {} };
|
||||
|
||||
BOOST_OPENMETHOD(
|
||||
poke, (virtual_ptr<Cat, release_registry>), void, debug_registry);
|
||||
|
||||
int main() {
|
||||
Cat felix;
|
||||
poke(felix);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -7,10 +7,16 @@
|
||||
|
||||
using namespace boost::openmethod;
|
||||
|
||||
struct Animal {};
|
||||
struct Animal { virtual ~Animal() {} };
|
||||
struct Cat : Animal {};
|
||||
|
||||
BOOST_OPENMETHOD(poke, (virtual_ptr<Animal>), void);
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(poke, (Cat&), void) {
|
||||
}
|
||||
|
||||
int main() {
|
||||
Cat felix;
|
||||
poke(felix);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -7,10 +7,16 @@
|
||||
|
||||
using namespace boost::openmethod;
|
||||
|
||||
struct Animal {};
|
||||
struct Animal { virtual ~Animal() {} };
|
||||
struct Cat : Animal {};
|
||||
|
||||
BOOST_OPENMETHOD(poke, (const virtual_ptr<Animal>&), void);
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(poke, (virtual_ptr<Cat>), void) {
|
||||
}
|
||||
|
||||
int main() {
|
||||
Cat felix;
|
||||
poke(felix);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -8,10 +8,16 @@
|
||||
|
||||
using namespace boost::openmethod;
|
||||
|
||||
struct Animal {};
|
||||
struct Animal { virtual ~Animal() {} };
|
||||
struct Cat : Animal {};
|
||||
|
||||
BOOST_OPENMETHOD(poke, (shared_virtual_ptr<Animal>&), void);
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(poke, (shared_virtual_ptr<Cat>&), void) {
|
||||
}
|
||||
|
||||
int main() {
|
||||
Cat felix;
|
||||
poke(felix);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -7,10 +7,16 @@
|
||||
|
||||
using namespace boost::openmethod;
|
||||
|
||||
struct Animal {};
|
||||
struct Animal { virtual ~Animal() {} };
|
||||
struct Cat : Animal {};
|
||||
|
||||
BOOST_OPENMETHOD(poke, (virtual_ptr<Animal>), void);
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(poke, (const virtual_ptr<Cat>&), void) {
|
||||
}
|
||||
|
||||
int main() {
|
||||
Cat felix;
|
||||
poke(felix);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -129,36 +129,11 @@ static_assert(
|
||||
struct registry1 : default_registry::with<unique<registry1>> {};
|
||||
struct registry2 : default_registry::with<unique<registry2>> {};
|
||||
|
||||
static_assert(
|
||||
detail::using_same_registry<registry1, virtual_ptr<a, registry1>>::value);
|
||||
|
||||
static_assert(detail::using_same_registry<registry1, int>::value);
|
||||
static_assert(
|
||||
!detail::using_same_registry<registry1, virtual_ptr<a, registry2>>::value);
|
||||
|
||||
static_assert(valid_method_parameter<default_registry, virtual_<a&>>::value);
|
||||
static_assert(
|
||||
valid_method_parameter<default_registry, virtual_<const a&>>::value);
|
||||
static_assert(valid_method_parameter<default_registry, int>::value);
|
||||
|
||||
struct non_polymorphic {};
|
||||
|
||||
static_assert(!valid_method_parameter<
|
||||
virtual_<non_polymorphic&>, default_registry>::value);
|
||||
|
||||
struct non_polymorphic_inplace_vptr {};
|
||||
|
||||
auto boost_openmethod_vptr(const non_polymorphic_inplace_vptr&, void*)
|
||||
-> vptr_type;
|
||||
|
||||
static_assert(
|
||||
valid_method_parameter<
|
||||
virtual_<non_polymorphic_inplace_vptr&>, default_registry>::value);
|
||||
|
||||
static_assert(valid_method_parameter<
|
||||
virtual_<const non_polymorphic_inplace_vptr&>,
|
||||
default_registry>::value);
|
||||
|
||||
// clang-format on
|
||||
|
||||
static_assert(std::is_same_v<
|
||||
|
||||
Reference in New Issue
Block a user