types/tagged: add 'visit' call
This commit is contained in:
parent
c9b5605213
commit
4a556af89d
@ -134,4 +134,71 @@ namespace cruft {
|
|||||||
cruft::max (sizeof (ValueT)...)
|
cruft::max (sizeof (ValueT)...)
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
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,
|
||||||
|
template <typename...> typename TaggedT,
|
||||||
|
typename ...ComponentsT
|
||||||
|
>
|
||||||
|
requires std::is_same_v<
|
||||||
|
std::remove_cvref_t<TaggedT<ComponentsT...>>,
|
||||||
|
tagged<ComponentsT...>
|
||||||
|
>
|
||||||
|
decltype (auto)
|
||||||
|
visit (
|
||||||
|
VisitorT &&visitor,
|
||||||
|
TaggedT<ComponentsT...> arg
|
||||||
|
) {
|
||||||
|
static_assert (IndexV < sizeof...(ComponentsT));
|
||||||
|
using nth_t = std::tuple_element_t<IndexV, std::tuple<ComponentsT...>>;
|
||||||
|
|
||||||
|
// 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 == sizeof...(ComponentsT)) {
|
||||||
|
return std::invoke (visitor, arg.template get<nth_t> ());
|
||||||
|
} 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> ());
|
||||||
|
} else {
|
||||||
|
return visit<IndexV+1> (
|
||||||
|
std::forward<VisitorT> (visitor),
|
||||||
|
arg
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename VisitorT,
|
||||||
|
template <typename...> typename TaggedT,
|
||||||
|
typename ...ComponentsT
|
||||||
|
>
|
||||||
|
requires std::is_same_v<
|
||||||
|
std::remove_cvref_t<TaggedT<ComponentsT...>>,
|
||||||
|
tagged<ComponentsT...>
|
||||||
|
>
|
||||||
|
decltype (auto)
|
||||||
|
visit (VisitorT &&visitor, TaggedT<ComponentsT...> arg)
|
||||||
|
{
|
||||||
|
static_assert (sizeof...(ComponentsT));
|
||||||
|
|
||||||
|
return detail::visit<0> (
|
||||||
|
std::forward<VisitorT> (visitor),
|
||||||
|
arg
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user