From 4a556af89ddd06e40b8a013e80e60de9fb3e7ded Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Wed, 1 Apr 2020 14:52:32 +1100 Subject: [PATCH] types/tagged: add 'visit' call --- types/tagged.hpp | 67 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/types/tagged.hpp b/types/tagged.hpp index 5133281f..9bf7b9fb 100644 --- a/types/tagged.hpp +++ b/types/tagged.hpp @@ -134,4 +134,71 @@ namespace cruft { 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 TaggedT, + typename ...ComponentsT + > + requires std::is_same_v< + std::remove_cvref_t>, + tagged + > + decltype (auto) + visit ( + VisitorT &&visitor, + TaggedT arg + ) { + static_assert (IndexV < sizeof...(ComponentsT)); + using nth_t = std::tuple_element_t>; + + // 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 ()); + } 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 ()); + } else { + return visit ( + std::forward (visitor), + arg + ); + } + } + } + } + + + template < + typename VisitorT, + template typename TaggedT, + typename ...ComponentsT + > + requires std::is_same_v< + std::remove_cvref_t>, + tagged + > + decltype (auto) + visit (VisitorT &&visitor, TaggedT arg) + { + static_assert (sizeof...(ComponentsT)); + + return detail::visit<0> ( + std::forward (visitor), + arg + ); + } }