types/tagged: simplify the implementation of detail::visit

This commit is contained in:
Danny Robson 2020-12-02 12:05:26 +10:00
parent fdd8723bf4
commit 12716e8cb2

View File

@ -162,46 +162,31 @@ namespace std {
namespace cruft {
namespace detail {
// If the tagged object matches the IndexV'th type in ComponentsT then
// invoke visitor with the object as the argument. Else, advance to
// the next index and try with that type.
//
// We assume that outside callers only call this function with an
// IndexV of 0 (so that we have assurances that every type is visited).
template <
std::size_t IndexV,
typename VisitorT,
typename TaggedT
>
template <typename VisitorT, typename TaggedT, typename HeadT, typename ...TailT>
requires (
std::is_invocable_v<
VisitorT,
decltype (std::declval<TaggedT> ().template get <HeadT>())
>
)
decltype (auto)
visit (
VisitorT &&visitor,
TaggedT &&arg
) {
static_assert (IndexV < std::tuple_size_v<std::remove_cvref_t<TaggedT>>);
using nth_t = std::tuple_element_t<IndexV, std::remove_reference_t<TaggedT>>;
// If we're the last valid index then we must be invoked because
// there's no other option. Do this, and (statically) avoid
// further recursion.
if constexpr (IndexV + 1 == std::tuple_size_v<std::remove_reference_t<TaggedT>>) {
return std::invoke (visitor, arg.template get<nth_t> ());
visit (VisitorT &&visitor, TaggedT &&arg)
{
if constexpr (sizeof ...(TailT) == 0) {
return std::invoke (std::forward<VisitorT> (visitor), arg.template get<HeadT> ());
} else {
// If the tag matches, then dispatch, else recurse with the
// next available type index.
if (arg.tag () == nth_t::tag) {
return std::invoke (visitor, arg.template get<nth_t> ());
if (arg.tag () == HeadT::tag) {
return std::invoke (std::forward<VisitorT> (visitor), arg.template get<HeadT> ());
} else {
return visit<IndexV+1> (
std::forward<VisitorT> (visitor),
arg
);
return visit<VisitorT, TaggedT, TailT...> (std::forward<VisitorT> (visitor), arg);
}
}
}
}
/// Call the invokable `VisitorT` with the value in the supplied tagged
/// union.
template <
typename VisitorT,
template <typename...> typename TaggedT,
@ -216,13 +201,15 @@ namespace cruft {
{
static_assert (sizeof...(ComponentsT));
return detail::visit<0> (
return detail::visit<VisitorT, TaggedT<ComponentsT...>&, ComponentsT...> (
std::forward<VisitorT> (visitor),
arg
);
}
/// Call the invokable `VisitorT` with the value in the supplied tagged
/// union.
template <
typename VisitorT,
template <typename...> typename TaggedT,
@ -237,7 +224,7 @@ namespace cruft {
{
static_assert (sizeof...(ComponentsT));
return detail::visit<0> (
return detail::visit<VisitorT, TaggedT<ComponentsT...> const&, ComponentsT...> (
std::forward<VisitorT> (visitor),
arg
);
@ -263,6 +250,7 @@ namespace cruft {
);
}
template <typename ...ComponentsT>
bool operator!= (tagged<ComponentsT...> const &lhs, tagged<ComponentsT...> const &rhs)
{