Skip to content

Commit

Permalink
Add: GetLeaf
Browse files Browse the repository at this point in the history
  • Loading branch information
huanmie committed Aug 6, 2022
1 parent 5d1abc3 commit c13c95d
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 0 deletions.
4 changes: 4 additions & 0 deletions TypeCast/TypeCast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,9 @@ int main()
std::visit(Dispatcher{}, TypeCast::InstanceOf<Derived4*, Derived3*, Derived2*, Derived1*>((Base*)&derived4));
std::visit(Dispatcher{}, TypeCast::InstanceOf<Derived1*, Derived2*, Derived3*, Derived4*>(&base));
std::visit(Dispatcher{}, TypeCast::InstanceOf<>((Base*)&derived4));

// Leaf class in inherit tree.
static_assert(std::is_same_v<std::tuple<Derived2*, Derived4*>, decltype(TypeCast::GetLeaf<Derived1*, Derived2*, Derived3*, Derived4*>())>);
std::visit(Dispatcher{}, TypeCast::InstanceOf((Base*)&derived4, TypeCast::GetLeaf<Derived1*, Derived2*, Derived3*, Derived4*>()));
return 0;
}
50 changes: 50 additions & 0 deletions TypeCast/TypeCast.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,43 @@ namespace TypeCast
else
InstanceOf<Rest...>(result, value);
}

template<typename... Rest>
struct AddTupleType {};

template<typename... Rest, typename Type>
struct AddTupleType<std::tuple<Rest...>, Type>
{
using type = std::tuple<Rest..., Type>;
};

template<int begin, typename... Rest, typename T>
auto GetLeafLayer1(T&& result)
{
if constexpr (begin == sizeof...(Rest))
return result;
else if constexpr (std::is_same_v<decltype(GetLeafLayer2<begin, 0>(std::tuple<Rest...>{})), void > )
return GetLeafLayer1<begin + 1, Rest...>(result);
else
{
typename AddTupleType<std::remove_reference_t<decltype(result)>, std::tuple_element_t<begin, std::tuple<Rest...>>>::type new_result;
return GetLeafLayer1<begin + 1, Rest...>(new_result);
}
}

template<int begin1, int begin2, typename... Rest>
auto GetLeafLayer2(const std::tuple<Rest...>& tuple)
{
if constexpr (begin2 == sizeof...(Rest))
return std::tuple_element_t<begin1, std::tuple<Rest...>>{};
else if constexpr (begin1 != begin2 && std::is_base_of_v<
std::remove_pointer_t<std::tuple_element_t<begin1, std::tuple<Rest...>>>,
std::remove_pointer_t<std::tuple_element_t<begin2, std::tuple<Rest...>>>
>)
return;
else
return GetLeafLayer2<begin1, begin2 + 1>(tuple);
}
}

template<typename... Rest, typename This>
Expand All @@ -26,4 +63,17 @@ namespace TypeCast
Detail::InstanceOf<Rest...>(result, value);
return result;
}

template<typename... Rest>
requires (std::is_pointer_v<Rest>&&...)
auto GetLeaf()
{
return Detail::GetLeafLayer1<0, Rest...>(std::tuple<>{});
}

template<typename... Rest, typename This>
std::variant<This, Rest...> InstanceOf(This&& value, const std::tuple<Rest...>& leaf)
{
return InstanceOf<Rest...>(std::remove_reference_t<This>(value));
}
}

0 comments on commit c13c95d

Please sign in to comment.