/******************************************************************************* * 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-2025, by Matvey Cherevko (blackmatov@gmail.com) ******************************************************************************/ #include #include namespace { struct A { A() = default; virtual ~A() = default; A(A&&) = delete; A(const A&) = delete; A& operator=(A&&) = delete; A& operator=(const A&) = delete; int i = 1; }; struct B : virtual A { int bi = 2; META_HPP_ENABLE_BASE_INFO(A) }; struct C : virtual A { int ci = 3; META_HPP_ENABLE_BASE_INFO(A) }; struct D : B, C { int di = 4; META_HPP_ENABLE_BASE_INFO(B, C) }; } TEST_CASE("meta/meta_utilities/arg5") { namespace meta = meta_hpp; // * <- B <- * // A D // * <- C <- * } TEST_CASE("meta/meta_utilities/arg5/cast") { namespace meta = meta_hpp; using meta::detail::uarg; using meta::detail::type_registry; type_registry& r{type_registry::instance()}; SUBCASE("int[2]") { int arr[2]{1,2}; CHECK(uarg(r, arr).get_raw_type() == meta::resolve_type(arr)); static_assert(std::is_invocable_v); static_assert(std::is_invocable_v); static_assert(std::is_invocable_v); static_assert(std::is_invocable_v); CHECK(uarg(r, arr).can_cast_to(r)); CHECK(uarg(r, arr).can_cast_to(r)); CHECK(uarg(r, arr).can_cast_to(r)); CHECK(uarg(r, arr).can_cast_to(r)); CHECK(uarg(r, arr).cast(r) == static_cast(arr)); CHECK(uarg(r, arr).cast(r) == static_cast(arr)); CHECK(uarg(r, arr).cast(r) == static_cast(arr)); CHECK(uarg(r, arr).cast(r) == static_cast(arr)); } SUBCASE("const int[2]") { const int arr[2]{1,2}; CHECK(uarg(r, arr).get_raw_type() == meta::resolve_type(arr)); static_assert(!std::is_invocable_v); static_assert(std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(std::is_invocable_v); CHECK_FALSE(uarg(r, arr).can_cast_to(r)); CHECK(uarg(r, arr).can_cast_to(r)); CHECK_FALSE(uarg(r, arr).can_cast_to(r)); CHECK(uarg(r, arr).can_cast_to(r)); // CHECK_THROWS(std::ignore = uarg(r, arr).cast(r)); CHECK(uarg(r, arr).cast(r) == static_cast(arr)); // CHECK_THROWS(std::ignore = uarg(r, arr).cast(r)); CHECK(uarg(r, arr).cast(r) == static_cast(arr)); } SUBCASE("D[2]") { D arr[2]; CHECK(uarg(r, arr).get_raw_type() == meta::resolve_type(arr)); static_assert(std::is_invocable_v); static_assert(std::is_invocable_v); static_assert(std::is_invocable_v); static_assert(std::is_invocable_v); CHECK(uarg(r, arr).can_cast_to(r)); CHECK(uarg(r, arr).can_cast_to(r)); CHECK(uarg(r, arr).can_cast_to(r)); CHECK(uarg(r, arr).can_cast_to(r)); CHECK(uarg(r, arr).cast(r) == static_cast(arr)); CHECK(uarg(r, arr).cast(r) == static_cast(arr)); CHECK(uarg(r, arr).cast(r) == static_cast(arr)); CHECK(uarg(r, arr).cast(r) == static_cast(arr)); } SUBCASE("const D[2]") { const D arr[2]; CHECK(uarg(r, arr).get_raw_type() == meta::resolve_type(arr)); static_assert(!std::is_invocable_v); static_assert(std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(std::is_invocable_v); CHECK_FALSE(uarg(r, arr).can_cast_to(r)); CHECK(uarg(r, arr).can_cast_to(r)); CHECK_FALSE(uarg(r, arr).can_cast_to(r)); CHECK(uarg(r, arr).can_cast_to(r)); // CHECK_THROWS(std::ignore = uarg(r, arr).cast(r)); CHECK(uarg(r, arr).cast(r) == static_cast(arr)); // CHECK_THROWS(std::ignore = uarg(r, arr).cast(r)); CHECK(uarg(r, arr).cast(r) == static_cast(arr)); } SUBCASE("&") { using T = D[2]; static T src{}; { auto LV = []() -> T& { return src; }; CHECK(uarg{r, LV()}.get_raw_type() == meta::resolve_type()); static_assert(std::is_invocable_v); static_assert(std::is_invocable_v); static_assert(std::is_invocable_v); static_assert(std::is_invocable_v); [](A*){}(LV()); [](const A*){}(LV()); [](A* const){}(LV()); [](const A* const){}(LV()); CHECK(uarg(r, LV()).cast(r) == static_cast(src)); CHECK(uarg(r, LV()).cast(r) == static_cast(src)); CHECK(uarg(r, LV()).cast(r) == static_cast(src)); CHECK(uarg(r, LV()).cast(r) == static_cast(src)); } { auto CLV = []() -> const T& { return src; }; CHECK(uarg{r, CLV()}.get_raw_type() == meta::resolve_type()); static_assert(!std::is_invocable_v); static_assert(std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(std::is_invocable_v); // CHECK_THROWS(std::ignore = uarg(r, CLV()).cast(r)); CHECK(uarg(r, CLV()).cast(r) == static_cast(src)); // CHECK_THROWS(std::ignore = uarg(r, CLV()).cast(r)); CHECK(uarg(r, CLV()).cast(r) == static_cast(src)); } { auto XV = []() -> T&& { return std::move(src); }; CHECK(uarg{r, XV()}.get_raw_type() == meta::resolve_type()); static_assert(std::is_invocable_v); static_assert(std::is_invocable_v); static_assert(std::is_invocable_v); static_assert(std::is_invocable_v); CHECK(uarg(r, XV()).cast(r) == static_cast(src)); CHECK(uarg(r, XV()).cast(r) == static_cast(src)); CHECK(uarg(r, XV()).cast(r) == static_cast(src)); CHECK(uarg(r, XV()).cast(r) == static_cast(src)); } { auto CXV = []() -> const T&& { return std::move(src); }; CHECK(uarg{r, CXV()}.get_raw_type() == meta::resolve_type()); static_assert(!std::is_invocable_v); static_assert(std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(std::is_invocable_v); // CHECK_THROWS(std::ignore = uarg(r, CXV()).cast(r)); CHECK(uarg(r, CXV()).cast(r) == static_cast(src)); // CHECK_THROWS(std::ignore = uarg(r, CXV()).cast(r)); CHECK(uarg(r, CXV()).cast(r) == static_cast(src)); } } SUBCASE("*") { { static D arr[2]{}; static_assert(std::is_invocable_v); static_assert(std::is_invocable_v); static_assert(std::is_invocable_v); static_assert(std::is_invocable_v); static_assert(std::is_invocable_v); static_assert(std::is_invocable_v); CHECK(uarg{r, arr}.can_cast_to(r)); CHECK(uarg{r, arr}.can_cast_to(r)); CHECK(uarg{r, &arr}.can_cast_to(r)); CHECK(uarg{r, &arr}.can_cast_to(r)); CHECK(uarg{r, &arr}.can_cast_to(r)); CHECK(uarg{r, &arr}.can_cast_to(r)); CHECK(&uarg{r, arr}.cast(r) == &arr); CHECK(&uarg{r, arr}.cast(r) == &arr); CHECK(uarg{r, &arr}.cast(r) == &arr); CHECK(uarg{r, &arr}.cast(r) == &arr); CHECK(uarg{r, &arr}.cast(r) == &arr); CHECK(uarg{r, &arr}.cast(r) == &arr); } { static const D arr[2]{}; static_assert(!std::is_invocable_v); static_assert(std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(std::is_invocable_v); CHECK_FALSE(uarg{r, arr}.can_cast_to(r)); CHECK(uarg{r, arr}.can_cast_to(r)); CHECK_FALSE(uarg{r, &arr}.can_cast_to(r)); CHECK(uarg{r, &arr}.can_cast_to(r)); CHECK_FALSE(uarg{r, &arr}.can_cast_to(r)); CHECK(uarg{r, &arr}.can_cast_to(r)); // CHECK_THROWS(std::ignore = &uarg{r, arr}.cast(r)); CHECK(&uarg{r, arr}.cast(r) == &arr); // CHECK_THROWS(std::ignore = uarg{r, &arr}.cast(r)); CHECK(uarg{r, &arr}.cast(r) == &arr); // CHECK_THROWS(std::ignore = uarg{r, &arr}.cast(r)); CHECK(uarg{r, &arr}.cast(r) == &arr); } } }