/******************************************************************************* * 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 #include namespace { struct A1 { A1() = default; A1(const A1&) = default; virtual ~A1() = default; char a{'a'}; META_HPP_ENABLE_POLYMORPHIC_CAST() }; struct B1 : A1 { B1() = default; B1(const B1&) = default; char b{'b'}; META_HPP_ENABLE_POLYMORPHIC_CAST() }; struct C1 : B1 { C1() = default; C1(const C1&) = default; char c{'c'}; META_HPP_ENABLE_POLYMORPHIC_CAST() }; // A1 <- B1 <- C1 struct A2 { A2() = default; A2(const A2&) = default; virtual ~A2() = default; char a{'a'}; META_HPP_ENABLE_POLYMORPHIC_CAST() }; struct B2 : virtual A2 { B2() = default; B2(const B2&) = default; char b{'b'}; META_HPP_ENABLE_POLYMORPHIC_CAST() }; struct C2 : virtual A2 { C2() = default; C2(const C2&) = default; char c{'c'}; META_HPP_ENABLE_POLYMORPHIC_CAST() }; struct D2 { D2() = default; D2(const D2&) = default; virtual ~D2() = default; char d{'d'}; META_HPP_ENABLE_POLYMORPHIC_CAST() }; struct E2 : D2 { E2() = default; E2(const E2&) = default; char e{'e'}; META_HPP_ENABLE_POLYMORPHIC_CAST() }; struct F2 : B2, C2, E2 { F2() = default; F2(const F2&) = default; char f{'f'}; META_HPP_ENABLE_POLYMORPHIC_CAST() }; // A2 <= B2 // <- // A2 <= C2 F2 // <- // D2 <- E2 namespace meta = meta_hpp; template < meta::detail::class_kind From, meta::detail::class_kind To, typename Value > [[maybe_unused]] void check_casts_impl(Value& value) { using from_void_cv = meta::detail::add_cv_t; from_void_cv* from_void_ptr = dynamic_cast(std::addressof(value)); REQUIRE(from_void_ptr == meta::ucast(std::addressof(value))); From* from_ptr = dynamic_cast(std::addressof(value)); REQUIRE(from_ptr == meta::ucast(std::addressof(value))); using to_void_cv = meta::detail::add_cv_t; to_void_cv* to_void_ptr = dynamic_cast(from_ptr); REQUIRE(to_void_ptr == meta::ucast(from_ptr)); To* to_ptr = dynamic_cast(from_ptr); REQUIRE(to_ptr == meta::ucast(from_ptr)); if ( from_ptr ) { if ( to_ptr ) { REQUIRE(to_ptr == std::addressof(meta::ucast(*from_ptr))); } else { REQUIRE_THROWS(meta::ucast(*from_ptr)); } } } template < meta::detail::class_kind From, meta::detail::class_kind To, typename Value > [[maybe_unused]] void check_casts(Value& value) { check_casts_impl(value); check_casts_impl(std::as_const(value)); } } TEST_CASE("meta/meta_utilities/ucast/_") { namespace meta = meta_hpp; meta::class_(); meta::class_().base_(); meta::class_().base_(); meta::class_(); meta::class_().base_(); meta::class_().base_(); meta::class_(); meta::class_().base_(); meta::class_().base_(); } TEST_CASE("meta/meta_utilities/ucast") { namespace meta = meta_hpp; #if defined(META_HPP_NO_RTTI) SUBCASE("1") { { C1 c; CHECK(meta::ucast(static_cast(&c))->a == 'a'); CHECK(meta::ucast(static_cast(&c))->b == 'b'); CHECK(meta::ucast(static_cast(&c))->c == 'c'); CHECK(meta::ucast(static_cast(&c))->a == 'a'); CHECK(meta::ucast(static_cast(&c))->b == 'b'); CHECK(meta::ucast(static_cast(&c))->c == 'c'); CHECK(meta::ucast(static_cast(&c))->a == 'a'); CHECK(meta::ucast(static_cast(&c))->b == 'b'); CHECK(meta::ucast(static_cast(&c))->c == 'c'); } { B1 b; CHECK(meta::ucast(static_cast(&b))->a == 'a'); CHECK(meta::ucast(static_cast(&b))->b == 'b'); CHECK_FALSE(meta::ucast(static_cast(&b))); CHECK(meta::ucast(static_cast(&b))->a == 'a'); CHECK(meta::ucast(static_cast(&b))->b == 'b'); CHECK_FALSE(meta::ucast(static_cast(&b))); } { A1 a; CHECK(meta::ucast(static_cast(&a))->a == 'a'); CHECK_FALSE(meta::ucast(static_cast(&a))); CHECK_FALSE(meta::ucast(static_cast(&a))); } } SUBCASE("2") { { F2 f; CHECK(meta::ucast(static_cast(&f))->a == 'a'); CHECK(meta::ucast(static_cast(&f))->b == 'b'); CHECK(meta::ucast(static_cast(&f))->c == 'c'); CHECK(meta::ucast(static_cast(&f))->d == 'd'); CHECK(meta::ucast(static_cast(&f))->e == 'e'); CHECK(meta::ucast(static_cast(&f))->a == 'a'); CHECK(meta::ucast(static_cast(&f))->b == 'b'); CHECK(meta::ucast(static_cast(&f))->c == 'c'); CHECK(meta::ucast(static_cast(&f))->d == 'd'); CHECK(meta::ucast(static_cast(&f))->e == 'e'); CHECK(meta::ucast(static_cast(&f))->a == 'a'); CHECK(meta::ucast(static_cast(&f))->b == 'b'); CHECK(meta::ucast(static_cast(&f))->c == 'c'); CHECK(meta::ucast(static_cast(&f))->d == 'd'); CHECK(meta::ucast(static_cast(&f))->e == 'e'); CHECK(meta::ucast(static_cast(&f))->a == 'a'); CHECK(meta::ucast(static_cast(&f))->b == 'b'); CHECK(meta::ucast(static_cast(&f))->c == 'c'); CHECK(meta::ucast(static_cast(&f))->d == 'd'); CHECK(meta::ucast(static_cast(&f))->e == 'e'); } { B2 b; CHECK(meta::ucast(static_cast(&b))->a == 'a'); CHECK(meta::ucast(static_cast(&b))->b == 'b'); CHECK_FALSE(meta::ucast(static_cast(&b))); CHECK_FALSE(meta::ucast(static_cast(&b))); CHECK_FALSE(meta::ucast(static_cast(&b))); CHECK(meta::ucast(static_cast(&b))->a == 'a'); CHECK(meta::ucast(static_cast(&b))->b == 'b'); CHECK_FALSE(meta::ucast(static_cast(&b))); CHECK_FALSE(meta::ucast(static_cast(&b))); CHECK_FALSE(meta::ucast(static_cast(&b))); } } #else SUBCASE("1") { { C1 c; check_casts(c); check_casts(c); check_casts(c); check_casts(c); check_casts(c); check_casts(c); check_casts(c); check_casts(c); check_casts(c); } { B1 b; check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); } { A1 a; check_casts(a); check_casts(a); check_casts(a); check_casts(a); check_casts(a); check_casts(a); check_casts(a); check_casts(a); check_casts(a); } } SUBCASE("2") { { F2 f; check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); check_casts(f); } { B2 b; check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); check_casts(b); } { E2 e; check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); check_casts(e); } { D2 d; check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); check_casts(d); } } #endif }