mirror of
https://github.com/BlackMATov/meta.hpp.git
synced 2025-12-13 11:17:06 +07:00
fix ambiguous casts issues
This commit is contained in:
@@ -2574,6 +2574,10 @@ namespace meta_hpp
|
||||
[[nodiscard]] bool is_direct_base_of() const noexcept;
|
||||
[[nodiscard]] bool is_direct_base_of(const class_type& derived) const noexcept;
|
||||
|
||||
template < detail::class_kind Derived >
|
||||
[[nodiscard]] bool is_virtual_base_of() const noexcept;
|
||||
[[nodiscard]] bool is_virtual_base_of(const class_type& derived) const noexcept;
|
||||
|
||||
template < detail::class_kind Base >
|
||||
[[nodiscard]] bool is_derived_from() const noexcept;
|
||||
[[nodiscard]] bool is_derived_from(const class_type& base) const noexcept;
|
||||
@@ -2582,6 +2586,10 @@ namespace meta_hpp
|
||||
[[nodiscard]] bool is_direct_derived_from() const noexcept;
|
||||
[[nodiscard]] bool is_direct_derived_from(const class_type& base) const noexcept;
|
||||
|
||||
template < detail::class_kind Base >
|
||||
[[nodiscard]] bool is_virtual_derived_from() const noexcept;
|
||||
[[nodiscard]] bool is_virtual_derived_from(const class_type& base) const noexcept;
|
||||
|
||||
[[nodiscard]] function get_function(std::string_view name) const noexcept;
|
||||
[[nodiscard]] member get_member(std::string_view name) const noexcept;
|
||||
[[nodiscard]] method get_method(std::string_view name) const noexcept;
|
||||
@@ -2800,17 +2808,28 @@ namespace meta_hpp::detail
|
||||
typedef_map typedefs;
|
||||
variable_set variables;
|
||||
|
||||
using upcast_func_t = void* (*)(void*);
|
||||
struct upcast_func_t final {
|
||||
void* (*upcast)(void*){};
|
||||
bool is_virtual_upcast{};
|
||||
class_type target_class{};
|
||||
|
||||
template < typename Derived, typename Base >
|
||||
requires std::is_base_of_v<Base, Derived>
|
||||
upcast_func_t(std::in_place_type_t<Derived>, std::in_place_type_t<Base>);
|
||||
|
||||
[[nodiscard]] void* apply(void* ptr) const noexcept;
|
||||
[[nodiscard]] const void* apply(const void* ptr) const noexcept;
|
||||
};
|
||||
|
||||
struct upcast_func_list_t final {
|
||||
class_set vbases;
|
||||
std::vector<upcast_func_t> upcasts;
|
||||
|
||||
upcast_func_list_t() = default;
|
||||
upcast_func_list_t(upcast_func_t _upcast);
|
||||
upcast_func_list_t(std::vector<upcast_func_t> _upcasts);
|
||||
upcast_func_list_t(const upcast_func_t& _upcast);
|
||||
upcast_func_list_t(class_set _vbases, std::vector<upcast_func_t> _upcasts);
|
||||
|
||||
void* apply(void* ptr) const noexcept;
|
||||
const void* apply(const void* ptr) const noexcept;
|
||||
[[nodiscard]] void* apply(void* ptr) const noexcept;
|
||||
[[nodiscard]] const void* apply(const void* ptr) const noexcept;
|
||||
|
||||
friend upcast_func_list_t operator+(const upcast_func_list_t& l, const upcast_func_list_t& r);
|
||||
};
|
||||
@@ -4861,13 +4880,14 @@ namespace meta_hpp::detail::class_bind_impl
|
||||
using derived_classes_db_t = std::map<class_type, class_set, std::less<>>;
|
||||
|
||||
template < class_kind Class, class_kind Base >
|
||||
requires detail::class_bind_base_kind<Class, Base>
|
||||
requires std::is_base_of_v<Base, Class>
|
||||
void update_new_bases_db( //
|
||||
new_bases_db_t& new_bases_db
|
||||
) {
|
||||
new_bases_db.emplace(resolve_type<Base>(), [](void* from) {
|
||||
return static_cast<void*>(static_cast<Base*>(static_cast<Class*>(from)));
|
||||
});
|
||||
new_bases_db.try_emplace( //
|
||||
resolve_type<Base>(),
|
||||
std::in_place_type<Class>,
|
||||
std::in_place_type<Base>);
|
||||
}
|
||||
|
||||
inline void update_deep_upcasts_db( //
|
||||
@@ -5722,8 +5742,19 @@ namespace meta_hpp::detail
|
||||
const class_type& base_class = base.as_class();
|
||||
const class_type& derived_class = derived.as_class();
|
||||
|
||||
if ( base_class && derived_class && base_class.is_base_of(derived_class) ) {
|
||||
return true;
|
||||
if ( base_class && derived_class ) {
|
||||
const class_type_data& derived_data = *type_access(derived_class);
|
||||
const class_type_data::deep_upcasts_t& deep_upcasts = derived_data.deep_upcasts;
|
||||
|
||||
if ( const auto iter{deep_upcasts.lower_bound(base)}; iter != deep_upcasts.end() && iter->first == base ) {
|
||||
if ( const auto next_iter{std::next(iter)}; next_iter == deep_upcasts.end() || next_iter->first != base ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( base_class.is_virtual_base_of(derived_class) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -5732,7 +5763,7 @@ namespace meta_hpp::detail
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
[[nodiscard]] inline void* pointer_upcast(void* ptr, const class_type& from, const class_type& to) {
|
||||
[[nodiscard]] inline void* unchecked_pointer_upcast(void* ptr, const class_type& from, const class_type& to) {
|
||||
if ( nullptr == ptr || !from || !to ) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -5741,32 +5772,24 @@ namespace meta_hpp::detail
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* base_ptr = nullptr;
|
||||
const class_type_data& from_data = *type_access(from);
|
||||
|
||||
class_type_data& from_data = *type_access(from);
|
||||
class_type_data::deep_upcasts_t& deep_upcasts = from_data.deep_upcasts;
|
||||
|
||||
for ( auto iter{deep_upcasts.lower_bound(to)}; iter != deep_upcasts.end() && iter->first == to; ++iter ) {
|
||||
if ( void* new_base_ptr{iter->second.apply(ptr)}; base_ptr == nullptr ) {
|
||||
base_ptr = new_base_ptr;
|
||||
} else if ( base_ptr != new_base_ptr ) {
|
||||
// ambiguous conversions
|
||||
return nullptr;
|
||||
}
|
||||
if ( auto iter{from_data.deep_upcasts.find(to)}; iter != from_data.deep_upcasts.end() ) {
|
||||
return iter->second.apply(ptr);
|
||||
}
|
||||
|
||||
return base_ptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline const void* pointer_upcast(const void* ptr, const class_type& from, const class_type& to) {
|
||||
[[nodiscard]] inline const void* unchecked_pointer_upcast(const void* ptr, const class_type& from, const class_type& to) {
|
||||
// NOLINTNEXTLINE(*-const-cast)
|
||||
return pointer_upcast(const_cast<void*>(ptr), from, to);
|
||||
return unchecked_pointer_upcast(const_cast<void*>(ptr), from, to);
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
[[nodiscard]] inline void* pointer_upcast(void* ptr, const any_type& from, const any_type& to) {
|
||||
[[nodiscard]] inline void* unchecked_pointer_upcast(void* ptr, const any_type& from, const any_type& to) {
|
||||
if ( nullptr == ptr || !from || !to ) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -5779,7 +5802,7 @@ namespace meta_hpp::detail
|
||||
const class_type& from_class = from.as_class();
|
||||
|
||||
if ( to_class && from_class ) {
|
||||
if ( void* base_ptr = pointer_upcast(ptr, from_class, to_class) ) {
|
||||
if ( void* base_ptr = unchecked_pointer_upcast(ptr, from_class, to_class) ) {
|
||||
return base_ptr;
|
||||
}
|
||||
}
|
||||
@@ -5787,17 +5810,17 @@ namespace meta_hpp::detail
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline const void* pointer_upcast(const void* ptr, const any_type& from, const any_type& to) {
|
||||
[[nodiscard]] inline const void* unchecked_pointer_upcast(const void* ptr, const any_type& from, const any_type& to) {
|
||||
// NOLINTNEXTLINE(*-const-cast)
|
||||
return pointer_upcast(const_cast<void*>(ptr), from, to);
|
||||
return unchecked_pointer_upcast(const_cast<void*>(ptr), from, to);
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
template < typename To, typename From >
|
||||
[[nodiscard]] To* pointer_upcast(type_registry& registry, From* ptr) {
|
||||
return static_cast<To*>(pointer_upcast( //
|
||||
[[nodiscard]] To* unchecked_pointer_upcast(type_registry& registry, From* ptr) {
|
||||
return static_cast<To*>(unchecked_pointer_upcast( //
|
||||
ptr,
|
||||
registry.resolve_type<From>(),
|
||||
registry.resolve_type<To>()
|
||||
@@ -5805,8 +5828,8 @@ namespace meta_hpp::detail
|
||||
}
|
||||
|
||||
template < typename To, typename From >
|
||||
[[nodiscard]] const To* pointer_upcast(type_registry& registry, const From* ptr) {
|
||||
return static_cast<const To*>(pointer_upcast( //
|
||||
[[nodiscard]] const To* unchecked_pointer_upcast(type_registry& registry, const From* ptr) {
|
||||
return static_cast<const To*>(unchecked_pointer_upcast( //
|
||||
ptr,
|
||||
registry.resolve_type<From>(),
|
||||
registry.resolve_type<To>()
|
||||
@@ -6059,21 +6082,27 @@ namespace meta_hpp::detail
|
||||
if ( from_type.is_array() ) {
|
||||
const array_type& from_type_array = from_type.as_array();
|
||||
|
||||
return static_cast<To>(pointer_upcast( //
|
||||
void* to_ptr = unchecked_pointer_upcast( //
|
||||
data_,
|
||||
from_type_array.get_data_type(),
|
||||
to_type_ptr.get_data_type()
|
||||
));
|
||||
);
|
||||
META_HPP_ASSERT(to_ptr);
|
||||
|
||||
return static_cast<To>(to_ptr);
|
||||
}
|
||||
|
||||
if ( from_type.is_pointer() ) {
|
||||
const pointer_type& from_type_ptr = from_type.as_pointer();
|
||||
|
||||
return static_cast<To>(pointer_upcast( //
|
||||
void* to_ptr = unchecked_pointer_upcast( //
|
||||
*static_cast<void**>(data_),
|
||||
from_type_ptr.get_data_type(),
|
||||
to_type_ptr.get_data_type()
|
||||
));
|
||||
);
|
||||
META_HPP_ASSERT(to_ptr);
|
||||
|
||||
return static_cast<To>(to_ptr);
|
||||
}
|
||||
|
||||
throw_exception(error_code::bad_argument_cast);
|
||||
@@ -6094,7 +6123,8 @@ namespace meta_hpp::detail
|
||||
const any_type& from_type = get_raw_type();
|
||||
const any_type& to_type = registry.resolve_type<to_raw_type>();
|
||||
|
||||
void* to_ptr = pointer_upcast(data_, from_type, to_type);
|
||||
void* to_ptr = unchecked_pointer_upcast(data_, from_type, to_type);
|
||||
META_HPP_ASSERT(to_ptr);
|
||||
|
||||
if constexpr ( std::is_lvalue_reference_v<To> ) {
|
||||
return *static_cast<to_raw_type_cv*>(to_ptr);
|
||||
@@ -6561,10 +6591,12 @@ namespace meta_hpp::detail
|
||||
const any_type& to_type = registry.resolve_type<inst_class>();
|
||||
|
||||
if ( from_type.is_class() && to_type.is_class() ) {
|
||||
const class_type& from_class = from_type.as_class();
|
||||
const class_type& to_class = to_type.as_class();
|
||||
|
||||
void* to_ptr = pointer_upcast(data_, from_class, to_class);
|
||||
void* to_ptr = unchecked_pointer_upcast( //
|
||||
data_,
|
||||
from_type.as_class(),
|
||||
to_type.as_class()
|
||||
);
|
||||
META_HPP_ASSERT(to_ptr);
|
||||
|
||||
if constexpr ( !std::is_reference_v<Q> ) {
|
||||
return *static_cast<inst_class_cv*>(to_ptr);
|
||||
@@ -6584,11 +6616,12 @@ namespace meta_hpp::detail
|
||||
const any_type& from_data_type = from_type_ptr.get_data_type();
|
||||
|
||||
if ( from_data_type.is_class() && to_type.is_class() ) {
|
||||
const class_type& from_data_class = from_data_type.as_class();
|
||||
const class_type& to_class = to_type.as_class();
|
||||
|
||||
void** from_data_ptr = static_cast<void**>(data_);
|
||||
void* to_ptr = pointer_upcast(*from_data_ptr, from_data_class, to_class);
|
||||
void* to_ptr = unchecked_pointer_upcast( //
|
||||
*static_cast<void**>(data_),
|
||||
from_data_type.as_class(),
|
||||
to_type.as_class()
|
||||
);
|
||||
META_HPP_ASSERT(to_ptr);
|
||||
|
||||
if constexpr ( !std::is_reference_v<Q> ) {
|
||||
return *static_cast<inst_class_cv*>(to_ptr);
|
||||
@@ -8121,16 +8154,45 @@ namespace meta_hpp::detail
|
||||
, size{class_traits<Class>::size}
|
||||
, align{class_traits<Class>::align}
|
||||
, argument_types{resolve_types(typename class_traits<Class>::argument_types{})} {}
|
||||
}
|
||||
|
||||
inline class_type_data::upcast_func_list_t::upcast_func_list_t(upcast_func_t _upcast)
|
||||
: upcasts{_upcast} {}
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
template < typename Derived, typename Base >
|
||||
requires std::is_base_of_v<Base, Derived>
|
||||
inline class_type_data::upcast_func_t::upcast_func_t(std::in_place_type_t<Derived>, std::in_place_type_t<Base>)
|
||||
: upcast{[](void* from) -> void* { return static_cast<Base*>(static_cast<Derived*>(from)); }}
|
||||
, is_virtual_upcast{is_virtual_base_of_v<Base, Derived>}
|
||||
, target_class{resolve_type<Base>()} {}
|
||||
|
||||
inline class_type_data::upcast_func_list_t::upcast_func_list_t(std::vector<upcast_func_t> _upcasts)
|
||||
: upcasts{std::move(_upcasts)} {}
|
||||
inline void* class_type_data::upcast_func_t::apply(void* ptr) const noexcept {
|
||||
return upcast(ptr);
|
||||
}
|
||||
|
||||
inline const void* class_type_data::upcast_func_t::apply(const void* ptr) const noexcept {
|
||||
// NOLINTNEXTLINE(*-const-cast)
|
||||
return apply(const_cast<void*>(ptr));
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
inline class_type_data::upcast_func_list_t::upcast_func_list_t(const upcast_func_t& _upcast)
|
||||
: upcasts{_upcast} {
|
||||
for ( const upcast_func_t& upcast : upcasts ) {
|
||||
if ( upcast.is_virtual_upcast ) {
|
||||
vbases.emplace(upcast.target_class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline class_type_data::upcast_func_list_t::upcast_func_list_t(class_set _vbases, std::vector<upcast_func_t> _upcasts)
|
||||
: vbases{std::move(_vbases)}
|
||||
, upcasts{std::move(_upcasts)} {}
|
||||
|
||||
inline void* class_type_data::upcast_func_list_t::apply(void* ptr) const noexcept {
|
||||
for ( upcast_func_t upcast : upcasts ) {
|
||||
ptr = upcast(ptr);
|
||||
for ( const upcast_func_t& upcast : upcasts ) {
|
||||
ptr = upcast.apply(ptr);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
@@ -8144,11 +8206,16 @@ namespace meta_hpp::detail
|
||||
const class_type_data::upcast_func_list_t& l,
|
||||
const class_type_data::upcast_func_list_t& r
|
||||
) {
|
||||
class_set new_vbases;
|
||||
new_vbases.insert(l.vbases.begin(), l.vbases.end());
|
||||
new_vbases.insert(r.vbases.begin(), r.vbases.end());
|
||||
|
||||
std::vector<class_type_data::upcast_func_t> new_upcasts;
|
||||
new_upcasts.reserve(l.upcasts.size() + r.upcasts.size());
|
||||
new_upcasts.insert(new_upcasts.end(), l.upcasts.begin(), l.upcasts.end());
|
||||
new_upcasts.insert(new_upcasts.end(), r.upcasts.begin(), r.upcasts.end());
|
||||
return class_type_data::upcast_func_list_t{std::move(new_upcasts)};
|
||||
|
||||
return class_type_data::upcast_func_list_t{std::move(new_vbases), std::move(new_upcasts)};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8271,13 +8338,38 @@ namespace meta_hpp
|
||||
return is_valid() && derived.is_valid() && derived.data_->base_upcasts.contains(*this);
|
||||
}
|
||||
|
||||
template < detail::class_kind Derived >
|
||||
bool class_type::is_virtual_base_of() const noexcept {
|
||||
return is_virtual_base_of(resolve_type<Derived>());
|
||||
}
|
||||
|
||||
inline bool class_type::is_virtual_base_of(const class_type& derived) const noexcept {
|
||||
if ( !is_valid() || !derived.is_valid() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const detail::class_type_data& derived_data = *derived.data_;
|
||||
const auto upcasts_range = derived_data.deep_upcasts.equal_range(*this);
|
||||
|
||||
if ( upcasts_range.first == upcasts_range.second ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const class_set& first_vbases = upcasts_range.first->second.vbases;
|
||||
return std::any_of(first_vbases.begin(), first_vbases.end(), [&upcasts_range](const class_type& vbase) {
|
||||
return std::all_of(std::next(upcasts_range.first), upcasts_range.second, [&vbase](auto&& upcasts_p) {
|
||||
return upcasts_p.second.vbases.contains(vbase);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
template < detail::class_kind Base >
|
||||
bool class_type::is_derived_from() const noexcept {
|
||||
return is_derived_from(resolve_type<Base>());
|
||||
}
|
||||
|
||||
inline bool class_type::is_derived_from(const class_type& base) const noexcept {
|
||||
return is_valid() && base.is_valid() && data_->deep_upcasts.contains(base);
|
||||
return base.is_base_of(*this);
|
||||
}
|
||||
|
||||
template < detail::class_kind Base >
|
||||
@@ -8286,7 +8378,16 @@ namespace meta_hpp
|
||||
}
|
||||
|
||||
inline bool class_type::is_direct_derived_from(const class_type& base) const noexcept {
|
||||
return is_valid() && base.is_valid() && data_->base_upcasts.contains(base);
|
||||
return base.is_direct_base_of(*this);
|
||||
}
|
||||
|
||||
template < detail::class_kind Base >
|
||||
bool class_type::is_virtual_derived_from() const noexcept {
|
||||
return is_virtual_derived_from(resolve_type<Base>());
|
||||
}
|
||||
|
||||
inline bool class_type::is_virtual_derived_from(const class_type& base) const noexcept {
|
||||
return base.is_virtual_base_of(*this);
|
||||
}
|
||||
|
||||
inline function class_type::get_function(std::string_view name) const noexcept {
|
||||
|
||||
96
develop/untests/meta_features/ambiguous_tests.cpp
Normal file
96
develop/untests/meta_features/ambiguous_tests.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
/*******************************************************************************
|
||||
* This file is part of the "https://github.com/blackmatov/meta.hpp"
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||
* Copyright (C) 2021-2023, by Matvey Cherevko (blackmatov@gmail.com)
|
||||
******************************************************************************/
|
||||
|
||||
#include <meta.hpp/meta_all.hpp>
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
struct A1 { std::string a1{"a1"}; };
|
||||
struct B1 : A1 { std::string b1{"b1"}; };
|
||||
struct C1 : A1 { std::string c1{"c1"}; };
|
||||
struct D1 : B1, C1 { std::string d1{"d1"}; };
|
||||
|
||||
struct A2 { std::string a2{"a2"}; };
|
||||
struct B2 : virtual A2 { std::string b2{"b2"}; };
|
||||
struct C2 : virtual A2 { std::string c2{"c2"}; };
|
||||
struct D2 : B2, C2 { std::string d2{"d2"}; };
|
||||
|
||||
struct A3 { std::string a3{"a3"}; };
|
||||
struct B3 : virtual A3 { std::string b3{"b3"}; };
|
||||
struct C3 : A3 { std::string c3{"c3"}; };
|
||||
struct D3 : B3, C3 { std::string d3{"d3"}; };
|
||||
}
|
||||
|
||||
TEST_CASE("meta/meta_features/ambiguous") {
|
||||
namespace meta = meta_hpp;
|
||||
|
||||
{
|
||||
meta::class_<B1>().base_<A1>();
|
||||
meta::class_<C1>().base_<A1>();
|
||||
meta::class_<D1>().base_<B1, C1>();
|
||||
|
||||
// A1 < B1
|
||||
// < D1
|
||||
// A1 < C1
|
||||
|
||||
static_assert(std::is_invocable_v<void(const A1&), A1&&>);
|
||||
static_assert(std::is_invocable_v<void(const A1&), B1&&>);
|
||||
static_assert(std::is_invocable_v<void(const A1&), C1&&>);
|
||||
static_assert(!std::is_invocable_v<void(const A1&), D1&&>);
|
||||
|
||||
CHECK(meta::is_invocable_with(+[](const A1&){}, A1{}));
|
||||
CHECK(meta::is_invocable_with(+[](const A1&){}, B1{}));
|
||||
CHECK(meta::is_invocable_with(+[](const A1&){}, C1{}));
|
||||
CHECK_FALSE(meta::is_invocable_with(+[](const A1&){}, D1{}));
|
||||
|
||||
CHECK_FALSE(meta::resolve_type<A1>().is_virtual_base_of<D1>());
|
||||
}
|
||||
|
||||
{
|
||||
meta::class_<B2>().base_<A2>();
|
||||
meta::class_<C2>().base_<A2>();
|
||||
meta::class_<D2>().base_<B2, C2>();
|
||||
|
||||
// A2 <= B2
|
||||
// < D2
|
||||
// A2 <= C2
|
||||
|
||||
static_assert(std::is_invocable_v<void(const A2&), A2&&>);
|
||||
static_assert(std::is_invocable_v<void(const A2&), B2&&>);
|
||||
static_assert(std::is_invocable_v<void(const A2&), C2&&>);
|
||||
static_assert(std::is_invocable_v<void(const A2&), D2&&>);
|
||||
|
||||
CHECK(meta::is_invocable_with(+[](const A2&){}, A2{}));
|
||||
CHECK(meta::is_invocable_with(+[](const A2&){}, B2{}));
|
||||
CHECK(meta::is_invocable_with(+[](const A2&){}, C2{}));
|
||||
CHECK(meta::is_invocable_with(+[](const A2&){}, D2{}));
|
||||
|
||||
CHECK(meta::resolve_type<A2>().is_virtual_base_of<D2>());
|
||||
}
|
||||
|
||||
{
|
||||
meta::class_<B3>().base_<A3>();
|
||||
meta::class_<C3>().base_<A3>();
|
||||
meta::class_<D3>().base_<B3, C3>();
|
||||
|
||||
// A3 <= B3
|
||||
// < D3
|
||||
// A3 < C3
|
||||
|
||||
static_assert(std::is_invocable_v<void(const A3&), A3&&>);
|
||||
static_assert(std::is_invocable_v<void(const A3&), B3&&>);
|
||||
static_assert(std::is_invocable_v<void(const A3&), C3&&>);
|
||||
static_assert(!std::is_invocable_v<void(const A3&), D3&&>);
|
||||
|
||||
CHECK(meta::is_invocable_with(+[](const A3&){}, A3{}));
|
||||
CHECK(meta::is_invocable_with(+[](const A3&){}, B3{}));
|
||||
CHECK(meta::is_invocable_with(+[](const A3&){}, C3{}));
|
||||
CHECK_FALSE(meta::is_invocable_with(+[](const A3&){}, D3{}));
|
||||
|
||||
CHECK_FALSE(meta::resolve_type<A3>().is_virtual_base_of<D3>());
|
||||
}
|
||||
}
|
||||
@@ -120,47 +120,47 @@ TEST_CASE("meta/meta_features/diamond") {
|
||||
CHECK(!E_type.is_derived_from(E_type));
|
||||
}
|
||||
|
||||
SUBCASE("pointer_upcast") {
|
||||
using meta::detail::pointer_upcast;
|
||||
SUBCASE("unchecked_pointer_upcast") {
|
||||
using meta::detail::unchecked_pointer_upcast;
|
||||
{
|
||||
A a;
|
||||
CHECK(pointer_upcast<A>(r, &a) == &a);
|
||||
CHECK_FALSE(pointer_upcast<B>(r, &a));
|
||||
CHECK_FALSE(pointer_upcast<C>(r, &a));
|
||||
CHECK_FALSE(pointer_upcast<D>(r, &a));
|
||||
CHECK_FALSE(pointer_upcast<E>(r, &a));
|
||||
CHECK(unchecked_pointer_upcast<A>(r, &a) == &a);
|
||||
CHECK_FALSE(unchecked_pointer_upcast<B>(r, &a));
|
||||
CHECK_FALSE(unchecked_pointer_upcast<C>(r, &a));
|
||||
CHECK_FALSE(unchecked_pointer_upcast<D>(r, &a));
|
||||
CHECK_FALSE(unchecked_pointer_upcast<E>(r, &a));
|
||||
}
|
||||
{
|
||||
const B b;
|
||||
CHECK(pointer_upcast<A>(r, &b) == &b);
|
||||
CHECK(pointer_upcast<B>(r, &b) == &b);
|
||||
CHECK_FALSE(pointer_upcast<C>(r, &b));
|
||||
CHECK_FALSE(pointer_upcast<D>(r, &b));
|
||||
CHECK_FALSE(pointer_upcast<E>(r, &b));
|
||||
CHECK(unchecked_pointer_upcast<A>(r, &b) == &b);
|
||||
CHECK(unchecked_pointer_upcast<B>(r, &b) == &b);
|
||||
CHECK_FALSE(unchecked_pointer_upcast<C>(r, &b));
|
||||
CHECK_FALSE(unchecked_pointer_upcast<D>(r, &b));
|
||||
CHECK_FALSE(unchecked_pointer_upcast<E>(r, &b));
|
||||
}
|
||||
{
|
||||
C c;
|
||||
CHECK(pointer_upcast<A>(r, &c) == &c);
|
||||
CHECK_FALSE(pointer_upcast<B>(r, &c));
|
||||
CHECK(pointer_upcast<C>(r, &c) == &c);
|
||||
CHECK_FALSE(pointer_upcast<D>(r, &c));
|
||||
CHECK_FALSE(pointer_upcast<E>(r, &c));
|
||||
CHECK(unchecked_pointer_upcast<A>(r, &c) == &c);
|
||||
CHECK_FALSE(unchecked_pointer_upcast<B>(r, &c));
|
||||
CHECK(unchecked_pointer_upcast<C>(r, &c) == &c);
|
||||
CHECK_FALSE(unchecked_pointer_upcast<D>(r, &c));
|
||||
CHECK_FALSE(unchecked_pointer_upcast<E>(r, &c));
|
||||
}
|
||||
{
|
||||
const D d;
|
||||
CHECK(pointer_upcast<A>(r, &d) == &d);
|
||||
CHECK(pointer_upcast<B>(r, &d) == &d);
|
||||
CHECK(pointer_upcast<C>(r, &d) == &d);
|
||||
CHECK(pointer_upcast<D>(r, &d) == &d);
|
||||
CHECK_FALSE(pointer_upcast<E>(r, &d));
|
||||
CHECK(unchecked_pointer_upcast<A>(r, &d) == &d);
|
||||
CHECK(unchecked_pointer_upcast<B>(r, &d) == &d);
|
||||
CHECK(unchecked_pointer_upcast<C>(r, &d) == &d);
|
||||
CHECK(unchecked_pointer_upcast<D>(r, &d) == &d);
|
||||
CHECK_FALSE(unchecked_pointer_upcast<E>(r, &d));
|
||||
}
|
||||
{
|
||||
E e;
|
||||
CHECK_FALSE(pointer_upcast<A>(r, &e));
|
||||
CHECK_FALSE(pointer_upcast<B>(r, &e));
|
||||
CHECK_FALSE(pointer_upcast<C>(r, &e));
|
||||
CHECK_FALSE(pointer_upcast<D>(r, &e));
|
||||
CHECK(pointer_upcast<E>(r, &e) == &e);
|
||||
CHECK_FALSE(unchecked_pointer_upcast<A>(r, &e));
|
||||
CHECK_FALSE(unchecked_pointer_upcast<B>(r, &e));
|
||||
CHECK_FALSE(unchecked_pointer_upcast<C>(r, &e));
|
||||
CHECK_FALSE(unchecked_pointer_upcast<D>(r, &e));
|
||||
CHECK(unchecked_pointer_upcast<E>(r, &e) == &e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -135,70 +135,70 @@ TEST_CASE("meta/meta_features/multiple2") {
|
||||
CHECK(!E1_type.is_base_of(E1_type));
|
||||
}
|
||||
|
||||
SUBCASE("pointer_upcast") {
|
||||
SUBCASE("unchecked_pointer_upcast") {
|
||||
using meta::detail::type_registry;
|
||||
using meta::detail::pointer_upcast;
|
||||
using meta::detail::unchecked_pointer_upcast;
|
||||
|
||||
type_registry& r{type_registry::instance()};
|
||||
|
||||
{
|
||||
A a;
|
||||
CHECK(pointer_upcast<A>(r, &a) == &a); CHECK(pointer_upcast<A>(r, &a)->a == "a");
|
||||
CHECK_FALSE(pointer_upcast<B0>(r, &a));
|
||||
CHECK_FALSE(pointer_upcast<B1>(r, &a));
|
||||
CHECK_FALSE(pointer_upcast<C>(r, &a));
|
||||
CHECK(unchecked_pointer_upcast<A>(r, &a) == &a); CHECK(unchecked_pointer_upcast<A>(r, &a)->a == "a");
|
||||
CHECK_FALSE(unchecked_pointer_upcast<B0>(r, &a));
|
||||
CHECK_FALSE(unchecked_pointer_upcast<B1>(r, &a));
|
||||
CHECK_FALSE(unchecked_pointer_upcast<C>(r, &a));
|
||||
}
|
||||
|
||||
{
|
||||
B0 b0;
|
||||
CHECK(pointer_upcast<A>(r, &b0) == &b0); CHECK(pointer_upcast<A>(r, &b0)->a == "a");
|
||||
CHECK(pointer_upcast<B0>(r, &b0) == &b0); CHECK(pointer_upcast<B0>(r, &b0)->b0 == "b0");
|
||||
CHECK_FALSE(pointer_upcast<B1>(r, &b0));
|
||||
CHECK_FALSE(pointer_upcast<C>(r, &b0));
|
||||
CHECK(unchecked_pointer_upcast<A>(r, &b0) == &b0); CHECK(unchecked_pointer_upcast<A>(r, &b0)->a == "a");
|
||||
CHECK(unchecked_pointer_upcast<B0>(r, &b0) == &b0); CHECK(unchecked_pointer_upcast<B0>(r, &b0)->b0 == "b0");
|
||||
CHECK_FALSE(unchecked_pointer_upcast<B1>(r, &b0));
|
||||
CHECK_FALSE(unchecked_pointer_upcast<C>(r, &b0));
|
||||
}
|
||||
|
||||
{
|
||||
B1 b1;
|
||||
CHECK(pointer_upcast<A>(r, &b1) == &b1); CHECK(pointer_upcast<A>(r, &b1)->a == "a");
|
||||
CHECK_FALSE(pointer_upcast<B0>(r, &b1));
|
||||
CHECK(pointer_upcast<B1>(r, &b1) == &b1); CHECK(pointer_upcast<B1>(r, &b1)->b1 == "b1");
|
||||
CHECK_FALSE(pointer_upcast<C>(r, &b1));
|
||||
CHECK(unchecked_pointer_upcast<A>(r, &b1) == &b1); CHECK(unchecked_pointer_upcast<A>(r, &b1)->a == "a");
|
||||
CHECK_FALSE(unchecked_pointer_upcast<B0>(r, &b1));
|
||||
CHECK(unchecked_pointer_upcast<B1>(r, &b1) == &b1); CHECK(unchecked_pointer_upcast<B1>(r, &b1)->b1 == "b1");
|
||||
CHECK_FALSE(unchecked_pointer_upcast<C>(r, &b1));
|
||||
}
|
||||
|
||||
{
|
||||
C c;
|
||||
CHECK(pointer_upcast<A>(r, &c) == &c); CHECK(pointer_upcast<A>(r, &c)->a == "a");
|
||||
CHECK(pointer_upcast<B0>(r, &c) == &c); CHECK(pointer_upcast<B0>(r, &c)->b0 == "b0");
|
||||
CHECK(pointer_upcast<B1>(r, &c) == &c); CHECK(pointer_upcast<B1>(r, &c)->b1 == "b1");
|
||||
CHECK(pointer_upcast<C>(r, &c) == &c); CHECK(pointer_upcast<C>(r, &c)->c == "c");
|
||||
CHECK_FALSE(pointer_upcast<D0>(r, &c));
|
||||
CHECK_FALSE(pointer_upcast<D1>(r, &c));
|
||||
CHECK_FALSE(pointer_upcast<E0>(r, &c));
|
||||
CHECK_FALSE(pointer_upcast<E1>(r, &c));
|
||||
CHECK(unchecked_pointer_upcast<A>(r, &c) == &c); CHECK(unchecked_pointer_upcast<A>(r, &c)->a == "a");
|
||||
CHECK(unchecked_pointer_upcast<B0>(r, &c) == &c); CHECK(unchecked_pointer_upcast<B0>(r, &c)->b0 == "b0");
|
||||
CHECK(unchecked_pointer_upcast<B1>(r, &c) == &c); CHECK(unchecked_pointer_upcast<B1>(r, &c)->b1 == "b1");
|
||||
CHECK(unchecked_pointer_upcast<C>(r, &c) == &c); CHECK(unchecked_pointer_upcast<C>(r, &c)->c == "c");
|
||||
CHECK_FALSE(unchecked_pointer_upcast<D0>(r, &c));
|
||||
CHECK_FALSE(unchecked_pointer_upcast<D1>(r, &c));
|
||||
CHECK_FALSE(unchecked_pointer_upcast<E0>(r, &c));
|
||||
CHECK_FALSE(unchecked_pointer_upcast<E1>(r, &c));
|
||||
}
|
||||
|
||||
{
|
||||
E0 e0;
|
||||
CHECK(pointer_upcast<A>(r, &e0) == &e0); CHECK(pointer_upcast<A>(r, &e0)->a == "a");
|
||||
CHECK(pointer_upcast<B0>(r, &e0) == &e0); CHECK(pointer_upcast<B0>(r, &e0)->b0 == "b0");
|
||||
CHECK(pointer_upcast<B1>(r, &e0) == &e0); CHECK(pointer_upcast<B1>(r, &e0)->b1 == "b1");
|
||||
CHECK(pointer_upcast<C>(r, &e0) == &e0); CHECK(pointer_upcast<C>(r, &e0)->c == "c");
|
||||
CHECK(pointer_upcast<D0>(r, &e0) == &e0); CHECK(pointer_upcast<D0>(r, &e0)->d0 == "d0");
|
||||
CHECK_FALSE(pointer_upcast<D1>(r, &e0));
|
||||
CHECK(pointer_upcast<E0>(r, &e0) == &e0); CHECK(pointer_upcast<E0>(r, &e0)->e0 == "e0");
|
||||
CHECK_FALSE(pointer_upcast<E1>(r, &e0));
|
||||
CHECK(unchecked_pointer_upcast<A>(r, &e0) == &e0); CHECK(unchecked_pointer_upcast<A>(r, &e0)->a == "a");
|
||||
CHECK(unchecked_pointer_upcast<B0>(r, &e0) == &e0); CHECK(unchecked_pointer_upcast<B0>(r, &e0)->b0 == "b0");
|
||||
CHECK(unchecked_pointer_upcast<B1>(r, &e0) == &e0); CHECK(unchecked_pointer_upcast<B1>(r, &e0)->b1 == "b1");
|
||||
CHECK(unchecked_pointer_upcast<C>(r, &e0) == &e0); CHECK(unchecked_pointer_upcast<C>(r, &e0)->c == "c");
|
||||
CHECK(unchecked_pointer_upcast<D0>(r, &e0) == &e0); CHECK(unchecked_pointer_upcast<D0>(r, &e0)->d0 == "d0");
|
||||
CHECK_FALSE(unchecked_pointer_upcast<D1>(r, &e0));
|
||||
CHECK(unchecked_pointer_upcast<E0>(r, &e0) == &e0); CHECK(unchecked_pointer_upcast<E0>(r, &e0)->e0 == "e0");
|
||||
CHECK_FALSE(unchecked_pointer_upcast<E1>(r, &e0));
|
||||
}
|
||||
|
||||
{
|
||||
E1 e1;
|
||||
CHECK(pointer_upcast<A>(r, &e1) == &e1); CHECK(pointer_upcast<A>(r, &e1)->a == "a");
|
||||
CHECK(pointer_upcast<B0>(r, &e1) == &e1); CHECK(pointer_upcast<B0>(r, &e1)->b0 == "b0");
|
||||
CHECK(pointer_upcast<B1>(r, &e1) == &e1); CHECK(pointer_upcast<B1>(r, &e1)->b1 == "b1");
|
||||
CHECK(pointer_upcast<C>(r, &e1) == &e1); CHECK(pointer_upcast<C>(r, &e1)->c == "c");
|
||||
CHECK_FALSE(pointer_upcast<D0>(r, &e1));
|
||||
CHECK(pointer_upcast<D1>(r, &e1) == &e1); CHECK(pointer_upcast<D1>(r, &e1)->d1 == "d1");
|
||||
CHECK_FALSE(pointer_upcast<E0>(r, &e1));
|
||||
CHECK(pointer_upcast<E1>(r, &e1) == &e1); CHECK(pointer_upcast<E1>(r, &e1)->e1 == "e1");
|
||||
CHECK(unchecked_pointer_upcast<A>(r, &e1) == &e1); CHECK(unchecked_pointer_upcast<A>(r, &e1)->a == "a");
|
||||
CHECK(unchecked_pointer_upcast<B0>(r, &e1) == &e1); CHECK(unchecked_pointer_upcast<B0>(r, &e1)->b0 == "b0");
|
||||
CHECK(unchecked_pointer_upcast<B1>(r, &e1) == &e1); CHECK(unchecked_pointer_upcast<B1>(r, &e1)->b1 == "b1");
|
||||
CHECK(unchecked_pointer_upcast<C>(r, &e1) == &e1); CHECK(unchecked_pointer_upcast<C>(r, &e1)->c == "c");
|
||||
CHECK_FALSE(unchecked_pointer_upcast<D0>(r, &e1));
|
||||
CHECK(unchecked_pointer_upcast<D1>(r, &e1) == &e1); CHECK(unchecked_pointer_upcast<D1>(r, &e1)->d1 == "d1");
|
||||
CHECK_FALSE(unchecked_pointer_upcast<E0>(r, &e1));
|
||||
CHECK(unchecked_pointer_upcast<E1>(r, &e1) == &e1); CHECK(unchecked_pointer_upcast<E1>(r, &e1)->e1 == "e1");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,65 +150,65 @@ TEST_CASE("meta/meta_features/multiple") {
|
||||
CHECK(!F_type.is_derived_from(F_type));
|
||||
}
|
||||
|
||||
SUBCASE("pointer_upcast") {
|
||||
using meta::detail::pointer_upcast;
|
||||
SUBCASE("unchecked_pointer_upcast") {
|
||||
using meta::detail::unchecked_pointer_upcast;
|
||||
{
|
||||
A a;
|
||||
CHECK(pointer_upcast<A>(r, &a) == &a);
|
||||
CHECK_FALSE(pointer_upcast<B>(r, &a));
|
||||
CHECK_FALSE(pointer_upcast<C>(r, &a));
|
||||
CHECK_FALSE(pointer_upcast<D>(r, &a));
|
||||
CHECK_FALSE(pointer_upcast<E>(r, &a));
|
||||
CHECK_FALSE(pointer_upcast<F>(r, &a));
|
||||
CHECK(unchecked_pointer_upcast<A>(r, &a) == &a);
|
||||
CHECK_FALSE(unchecked_pointer_upcast<B>(r, &a));
|
||||
CHECK_FALSE(unchecked_pointer_upcast<C>(r, &a));
|
||||
CHECK_FALSE(unchecked_pointer_upcast<D>(r, &a));
|
||||
CHECK_FALSE(unchecked_pointer_upcast<E>(r, &a));
|
||||
CHECK_FALSE(unchecked_pointer_upcast<F>(r, &a));
|
||||
}
|
||||
{
|
||||
const B b;
|
||||
CHECK(pointer_upcast<A>(r, &b) == &b);
|
||||
CHECK(pointer_upcast<B>(r, &b) == &b);
|
||||
CHECK_FALSE(pointer_upcast<C>(r, &b));
|
||||
CHECK_FALSE(pointer_upcast<D>(r, &b));
|
||||
CHECK_FALSE(pointer_upcast<E>(r, &b));
|
||||
CHECK_FALSE(pointer_upcast<F>(r, &b));
|
||||
CHECK(unchecked_pointer_upcast<A>(r, &b) == &b);
|
||||
CHECK(unchecked_pointer_upcast<B>(r, &b) == &b);
|
||||
CHECK_FALSE(unchecked_pointer_upcast<C>(r, &b));
|
||||
CHECK_FALSE(unchecked_pointer_upcast<D>(r, &b));
|
||||
CHECK_FALSE(unchecked_pointer_upcast<E>(r, &b));
|
||||
CHECK_FALSE(unchecked_pointer_upcast<F>(r, &b));
|
||||
}
|
||||
{
|
||||
C c;
|
||||
CHECK(pointer_upcast<A>(r, &c) == &c);
|
||||
CHECK_FALSE(pointer_upcast<B>(r, &c));
|
||||
CHECK(pointer_upcast<C>(r, &c) == &c);
|
||||
CHECK_FALSE(pointer_upcast<D>(r, &c));
|
||||
CHECK_FALSE(pointer_upcast<E>(r, &c));
|
||||
CHECK_FALSE(pointer_upcast<F>(r, &c));
|
||||
CHECK(unchecked_pointer_upcast<A>(r, &c) == &c);
|
||||
CHECK_FALSE(unchecked_pointer_upcast<B>(r, &c));
|
||||
CHECK(unchecked_pointer_upcast<C>(r, &c) == &c);
|
||||
CHECK_FALSE(unchecked_pointer_upcast<D>(r, &c));
|
||||
CHECK_FALSE(unchecked_pointer_upcast<E>(r, &c));
|
||||
CHECK_FALSE(unchecked_pointer_upcast<F>(r, &c));
|
||||
}
|
||||
{
|
||||
const D d;
|
||||
CHECK_FALSE(pointer_upcast<A>(r,&d));
|
||||
CHECK(pointer_upcast<A>(r, pointer_upcast<B>(r,&d)) == static_cast<const A*>(static_cast<const B*>(&d)));
|
||||
CHECK(pointer_upcast<A>(r, pointer_upcast<C>(r,&d)) == static_cast<const A*>(static_cast<const C*>(&d)));
|
||||
CHECK(pointer_upcast<B>(r, &d) == &d);
|
||||
CHECK(pointer_upcast<C>(r, &d) == &d);
|
||||
CHECK(pointer_upcast<D>(r, &d) == &d);
|
||||
CHECK_FALSE(pointer_upcast<E>(r, &d));
|
||||
CHECK_FALSE(pointer_upcast<F>(r, &d));
|
||||
// CHECK_FALSE(unchecked_pointer_upcast<A>(r,&d)); // ambiguous
|
||||
CHECK(unchecked_pointer_upcast<A>(r, unchecked_pointer_upcast<B>(r,&d)) == static_cast<const A*>(static_cast<const B*>(&d)));
|
||||
CHECK(unchecked_pointer_upcast<A>(r, unchecked_pointer_upcast<C>(r,&d)) == static_cast<const A*>(static_cast<const C*>(&d)));
|
||||
CHECK(unchecked_pointer_upcast<B>(r, &d) == &d);
|
||||
CHECK(unchecked_pointer_upcast<C>(r, &d) == &d);
|
||||
CHECK(unchecked_pointer_upcast<D>(r, &d) == &d);
|
||||
CHECK_FALSE(unchecked_pointer_upcast<E>(r, &d));
|
||||
CHECK_FALSE(unchecked_pointer_upcast<F>(r, &d));
|
||||
}
|
||||
{
|
||||
const E e;
|
||||
CHECK_FALSE(pointer_upcast<A>(r,&e));
|
||||
CHECK(pointer_upcast<A>(r, pointer_upcast<B>(r,&e)) == static_cast<const A*>(static_cast<const B*>(&e)));
|
||||
CHECK(pointer_upcast<A>(r, pointer_upcast<C>(r,&e)) == static_cast<const A*>(static_cast<const C*>(&e)));
|
||||
CHECK(pointer_upcast<B>(r, &e) == &e);
|
||||
CHECK(pointer_upcast<C>(r, &e) == &e);
|
||||
CHECK(pointer_upcast<D>(r, &e) == &e);
|
||||
CHECK(pointer_upcast<E>(r, &e) == &e);
|
||||
CHECK_FALSE(pointer_upcast<F>(r, &e));
|
||||
// CHECK_FALSE(unchecked_pointer_upcast<A>(r,&e)); // ambiguous
|
||||
CHECK(unchecked_pointer_upcast<A>(r, unchecked_pointer_upcast<B>(r,&e)) == static_cast<const A*>(static_cast<const B*>(&e)));
|
||||
CHECK(unchecked_pointer_upcast<A>(r, unchecked_pointer_upcast<C>(r,&e)) == static_cast<const A*>(static_cast<const C*>(&e)));
|
||||
CHECK(unchecked_pointer_upcast<B>(r, &e) == &e);
|
||||
CHECK(unchecked_pointer_upcast<C>(r, &e) == &e);
|
||||
CHECK(unchecked_pointer_upcast<D>(r, &e) == &e);
|
||||
CHECK(unchecked_pointer_upcast<E>(r, &e) == &e);
|
||||
CHECK_FALSE(unchecked_pointer_upcast<F>(r, &e));
|
||||
}
|
||||
{
|
||||
F f;
|
||||
CHECK_FALSE(pointer_upcast<A>(r, &f));
|
||||
CHECK_FALSE(pointer_upcast<B>(r, &f));
|
||||
CHECK_FALSE(pointer_upcast<C>(r, &f));
|
||||
CHECK_FALSE(pointer_upcast<D>(r, &f));
|
||||
CHECK_FALSE(pointer_upcast<E>(r, &f));
|
||||
CHECK(pointer_upcast<F>(r, &f) == &f);
|
||||
CHECK_FALSE(unchecked_pointer_upcast<A>(r, &f));
|
||||
CHECK_FALSE(unchecked_pointer_upcast<B>(r, &f));
|
||||
CHECK_FALSE(unchecked_pointer_upcast<C>(r, &f));
|
||||
CHECK_FALSE(unchecked_pointer_upcast<D>(r, &f));
|
||||
CHECK_FALSE(unchecked_pointer_upcast<E>(r, &f));
|
||||
CHECK(unchecked_pointer_upcast<F>(r, &f) == &f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,30 +9,91 @@
|
||||
|
||||
namespace
|
||||
{
|
||||
struct A {};
|
||||
struct B : A {};
|
||||
struct C : A {};
|
||||
struct D : B, C {};
|
||||
struct A1 {};
|
||||
struct B1 : A1 {};
|
||||
struct C1 : A1 {};
|
||||
struct D1 : B1, C1 {};
|
||||
|
||||
// A1 <- B1 <- *
|
||||
// D1
|
||||
// A1 <- C1 <- *
|
||||
|
||||
struct A2 {};
|
||||
struct B2 : virtual A2 {};
|
||||
struct C2 : virtual B2 {};
|
||||
struct D2 : virtual B2 {};
|
||||
struct E2 : C2, D2 {};
|
||||
|
||||
// A2 <= B2 <= C2 <- *
|
||||
// E2
|
||||
// A2 <= B2 <= D2 <- *
|
||||
|
||||
struct A3 {};
|
||||
struct B3 : virtual A3 {};
|
||||
struct C3 : A3 {};
|
||||
struct D3 : B3, C3 {};
|
||||
|
||||
// A3 <= B3 <- *
|
||||
// D3
|
||||
// A3 <- C3 <- *
|
||||
|
||||
// A * <- B <- *
|
||||
// D
|
||||
// A * <- C <- *
|
||||
}
|
||||
|
||||
TEST_CASE("meta/meta_issues/random/1") {
|
||||
namespace meta = meta_hpp;
|
||||
|
||||
meta::class_<B>().base_<A>();
|
||||
meta::class_<C>().base_<A>();
|
||||
meta::class_<D>().base_<B, C>();
|
||||
{
|
||||
meta::class_<B1>().base_<A1>();
|
||||
meta::class_<C1>().base_<A1>();
|
||||
meta::class_<D1>().base_<B1, C1>();
|
||||
|
||||
CHECK(meta::is_invocable_with(+[](const D&){ return true; }, D{}));
|
||||
CHECK(meta::is_invocable_with(+[](const C&){ return true; }, D{}));
|
||||
CHECK(meta::is_invocable_with(+[](const B&){ return true; }, D{}));
|
||||
CHECK_FALSE(meta::is_invocable_with(+[](const A&){ return true; }, D{}));
|
||||
CHECK(meta::is_invocable_with(+[](const D1&){ return true; }, D1{}));
|
||||
CHECK(meta::is_invocable_with(+[](const C1&){ return true; }, D1{}));
|
||||
CHECK(meta::is_invocable_with(+[](const B1&){ return true; }, D1{}));
|
||||
CHECK_FALSE(meta::is_invocable_with(+[](const A1&){ return true; }, D1{}));
|
||||
|
||||
CHECK(meta::try_invoke(+[](const D&){ return true; }, D{}));
|
||||
CHECK(meta::try_invoke(+[](const C&){ return true; }, D{}));
|
||||
CHECK(meta::try_invoke(+[](const B&){ return true; }, D{}));
|
||||
CHECK_FALSE(meta::try_invoke(+[](const A&){ return true; }, D{}));
|
||||
CHECK(meta::try_invoke(+[](const D1&){ return true; }, D1{}));
|
||||
CHECK(meta::try_invoke(+[](const C1&){ return true; }, D1{}));
|
||||
CHECK(meta::try_invoke(+[](const B1&){ return true; }, D1{}));
|
||||
CHECK_FALSE(meta::try_invoke(+[](const A1&){ return true; }, D1{}));
|
||||
|
||||
CHECK_FALSE(meta::resolve_type<A1>().is_virtual_base_of<D1>());
|
||||
}
|
||||
|
||||
{
|
||||
meta::class_<B2>().base_<A2>();
|
||||
meta::class_<C2>().base_<B2>();
|
||||
meta::class_<D2>().base_<B2>();
|
||||
meta::class_<E2>().base_<C2, D2>();
|
||||
|
||||
CHECK(meta::is_invocable_with(+[](const A2&){ return true; }, E2{}));
|
||||
CHECK(meta::is_invocable_with(+[](const B2&){ return true; }, E2{}));
|
||||
CHECK(meta::is_invocable_with(+[](const C2&){ return true; }, E2{}));
|
||||
CHECK(meta::is_invocable_with(+[](const D2&){ return true; }, E2{}));
|
||||
|
||||
CHECK(meta::try_invoke(+[](const A2&){ return true; }, E2{}));
|
||||
CHECK(meta::try_invoke(+[](const B2&){ return true; }, E2{}));
|
||||
CHECK(meta::try_invoke(+[](const C2&){ return true; }, E2{}));
|
||||
CHECK(meta::try_invoke(+[](const D2&){ return true; }, E2{}));
|
||||
|
||||
CHECK(meta::resolve_type<A2>().is_virtual_base_of<E2>());
|
||||
}
|
||||
|
||||
{
|
||||
meta::class_<B3>().base_<A3>();
|
||||
meta::class_<C3>().base_<A3>();
|
||||
meta::class_<D3>().base_<B3, C3>();
|
||||
|
||||
static_assert(std::is_invocable_v<void(A3*), A3*>);
|
||||
static_assert(std::is_invocable_v<void(A3*), B3*>);
|
||||
static_assert(std::is_invocable_v<void(A3*), C3*>);
|
||||
static_assert(!std::is_invocable_v<void(A3*), D3*>);
|
||||
|
||||
CHECK(meta::is_invocable_with(+[](const A3&){ return true; }, A3{}));
|
||||
CHECK(meta::is_invocable_with(+[](const A3&){ return true; }, B3{}));
|
||||
CHECK(meta::is_invocable_with(+[](const A3&){ return true; }, C3{}));
|
||||
CHECK_FALSE(meta::is_invocable_with(+[](const A3&){ return true; }, D3{}));
|
||||
|
||||
CHECK_FALSE(meta::resolve_type<A3>().is_virtual_base_of<D3>());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user