types/tagged: simplify the implementation of detail::visit
This commit is contained in:
parent
fdd8723bf4
commit
12716e8cb2
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user