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 cruft {
namespace detail { namespace detail {
// If the tagged object matches the IndexV'th type in ComponentsT then template <typename VisitorT, typename TaggedT, typename HeadT, typename ...TailT>
// invoke visitor with the object as the argument. Else, advance to requires (
// the next index and try with that type. std::is_invocable_v<
// VisitorT,
// We assume that outside callers only call this function with an decltype (std::declval<TaggedT> ().template get <HeadT>())
// IndexV of 0 (so that we have assurances that every type is visited). >
template < )
std::size_t IndexV,
typename VisitorT,
typename TaggedT
>
decltype (auto) decltype (auto)
visit ( visit (VisitorT &&visitor, TaggedT &&arg)
VisitorT &&visitor, {
TaggedT &&arg if constexpr (sizeof ...(TailT) == 0) {
) { return std::invoke (std::forward<VisitorT> (visitor), arg.template get<HeadT> ());
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> ());
} else { } else {
// If the tag matches, then dispatch, else recurse with the if (arg.tag () == HeadT::tag) {
// next available type index. return std::invoke (std::forward<VisitorT> (visitor), arg.template get<HeadT> ());
if (arg.tag () == nth_t::tag) {
return std::invoke (visitor, arg.template get<nth_t> ());
} else { } else {
return visit<IndexV+1> ( return visit<VisitorT, TaggedT, TailT...> (std::forward<VisitorT> (visitor), arg);
std::forward<VisitorT> (visitor),
arg
);
} }
} }
} }
} }
/// Call the invokable `VisitorT` with the value in the supplied tagged
/// union.
template < template <
typename VisitorT, typename VisitorT,
template <typename...> typename TaggedT, template <typename...> typename TaggedT,
@ -216,13 +201,15 @@ namespace cruft {
{ {
static_assert (sizeof...(ComponentsT)); static_assert (sizeof...(ComponentsT));
return detail::visit<0> ( return detail::visit<VisitorT, TaggedT<ComponentsT...>&, ComponentsT...> (
std::forward<VisitorT> (visitor), std::forward<VisitorT> (visitor),
arg arg
); );
} }
/// Call the invokable `VisitorT` with the value in the supplied tagged
/// union.
template < template <
typename VisitorT, typename VisitorT,
template <typename...> typename TaggedT, template <typename...> typename TaggedT,
@ -237,7 +224,7 @@ namespace cruft {
{ {
static_assert (sizeof...(ComponentsT)); static_assert (sizeof...(ComponentsT));
return detail::visit<0> ( return detail::visit<VisitorT, TaggedT<ComponentsT...> const&, ComponentsT...> (
std::forward<VisitorT> (visitor), std::forward<VisitorT> (visitor),
arg arg
); );
@ -263,6 +250,7 @@ namespace cruft {
); );
} }
template <typename ...ComponentsT> template <typename ...ComponentsT>
bool operator!= (tagged<ComponentsT...> const &lhs, tagged<ComponentsT...> const &rhs) bool operator!= (tagged<ComponentsT...> const &lhs, tagged<ComponentsT...> const &rhs)
{ {