types/tagged: support cvref in visit

This commit is contained in:
Danny Robson 2020-09-22 07:53:58 +10:00
parent a392ca1aa9
commit 2d6d924d66

View File

@ -14,6 +14,8 @@
#include "../maths.hpp" #include "../maths.hpp"
#include "../tuple/type.hpp" #include "../tuple/type.hpp"
#include <tuple>
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
namespace cruft { namespace cruft {
@ -64,6 +66,7 @@ namespace cruft {
tagged (tagged &&) = default; tagged (tagged &&) = default;
tagged& operator= (tagged const&) = default; tagged& operator= (tagged const&) = default;
tagged& operator= (tagged &) = default;
tagged& operator= (tagged &&) = default; tagged& operator= (tagged &&) = default;
@ -134,8 +137,30 @@ namespace cruft {
cruft::max (sizeof (ValueT)...) cruft::max (sizeof (ValueT)...)
]; ];
}; };
}
namespace std {
template <typename ...ComponentT>
struct tuple_size<::cruft::tagged<ComponentT...>>
: std::integral_constant<::std::size_t, sizeof...(ComponentT)>
{ ; };
template <std::size_t I, typename ...ComponentT>
struct tuple_element<
I,
::cruft::tagged<ComponentT...>
>
: ::std::tuple_element<
I,
std::tuple<ComponentT...>
>
{ ; };
}
namespace cruft {
namespace detail { namespace detail {
// If the tagged object matches the IndexV'th type in ComponentsT then // If the tagged object matches the IndexV'th type in ComponentsT then
// invoke visitor with the object as the argument. Else, advance to // invoke visitor with the object as the argument. Else, advance to
@ -146,25 +171,20 @@ namespace cruft {
template < template <
std::size_t IndexV, std::size_t IndexV,
typename VisitorT, typename VisitorT,
template <typename...> typename TaggedT, typename TaggedT
typename ...ComponentsT
>
requires std::is_same_v<
std::remove_cvref_t<TaggedT<ComponentsT...>>,
tagged<ComponentsT...>
> >
decltype (auto) decltype (auto)
visit ( visit (
VisitorT &&visitor, VisitorT &&visitor,
TaggedT<ComponentsT...> arg TaggedT &&arg
) { ) {
static_assert (IndexV < sizeof...(ComponentsT)); static_assert (IndexV < std::tuple_size_v<std::remove_cvref_t<TaggedT>>);
using nth_t = std::tuple_element_t<IndexV, std::tuple<ComponentsT...>>; 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 // If we're the last valid index then we must be invoked because
// there's no other option. Do this, and (statically) avoid // there's no other option. Do this, and (statically) avoid
// further recursion. // further recursion.
if constexpr (IndexV + 1 == sizeof...(ComponentsT)) { if constexpr (IndexV + 1 == std::tuple_size_v<std::remove_reference_t<TaggedT>>) {
return std::invoke (visitor, arg.template get<nth_t> ()); return std::invoke (visitor, arg.template get<nth_t> ());
} else { } else {
// If the tag matches, then dispatch, else recurse with the // If the tag matches, then dispatch, else recurse with the
@ -192,7 +212,28 @@ namespace cruft {
tagged<ComponentsT...> tagged<ComponentsT...>
> >
decltype (auto) decltype (auto)
visit (VisitorT &&visitor, TaggedT<ComponentsT...> arg) visit (VisitorT &&visitor, TaggedT<ComponentsT...> &arg)
{
static_assert (sizeof...(ComponentsT));
return detail::visit<0> (
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...> const &arg)
{ {
static_assert (sizeof...(ComponentsT)); static_assert (sizeof...(ComponentsT));