Add support for visit<R>

This commit is contained in:
Peter Dimov
2020-06-03 17:00:13 +03:00
parent bede3777a8
commit 5586ebaa64
3 changed files with 138 additions and 23 deletions

View File

@@ -2009,11 +2009,26 @@ template<class L> using front_if_same = mp11::mp_if<mp11::mp_apply<mp11::mp_same
template<class V> using apply_cv_ref = mp11::mp_product<copy_cv_ref_t, extract_variant_base<V>, mp11::mp_list<V>>;
template<class F, class... V> using Vret = front_if_same<mp11::mp_product_q<Qret<F>, apply_cv_ref<V>...>>;
struct deduced {};
#if !BOOST_WORKAROUND( BOOST_MSVC, < 1920 )
template<class R, class F, class... V> using Vret = mp11::mp_eval_if_not< std::is_same<R, deduced>, R, front_if_same, mp11::mp_product_q<Qret<F>, apply_cv_ref<V>...> >;
#else
template<class R, class F, class... V> struct Vret_impl
{
using type = mp11::mp_eval_if_not< std::is_same<R, deduced>, R, front_if_same, mp11::mp_product_q<Qret<F>, apply_cv_ref<V>...> >;
};
template<class R, class F, class... V> using Vret = typename Vret_impl<R, F, V...>::type;
#endif
} // namespace detail
template<class F> constexpr auto visit( F&& f ) -> decltype(std::forward<F>(f)())
template<class R = detail::deduced, class F> constexpr auto visit( F&& f ) -> detail::Vret<R, F>
{
return std::forward<F>(f)();
}
@@ -2021,12 +2036,12 @@ template<class F> constexpr auto visit( F&& f ) -> decltype(std::forward<F>(f)()
namespace detail
{
template<class F, class V1> struct visit_L1
template<class R, class F, class V1> struct visit_L1
{
F&& f;
V1&& v1;
template<class I> auto operator()( I ) const -> Vret<F, V1>
template<class I> auto operator()( I ) const -> Vret<R, F, V1>
{
return std::forward<F>(f)( unsafe_get<I::value>( std::forward<V1>(v1) ) );
}
@@ -2034,9 +2049,9 @@ template<class F, class V1> struct visit_L1
} // namespace detail
template<class F, class V1> constexpr auto visit( F&& f, V1&& v1 ) -> detail::Vret<F, V1>
template<class R = detail::deduced, class F, class V1> constexpr auto visit( F&& f, V1&& v1 ) -> detail::Vret<R, F, V1>
{
return mp11::mp_with_index<detail::variant_base_size<V1>>( v1.index(), detail::visit_L1<F, V1>{ std::forward<F>(f), std::forward<V1>(v1) } );
return mp11::mp_with_index<detail::variant_base_size<V1>>( v1.index(), detail::visit_L1<R, F, V1>{ std::forward<F>(f), std::forward<V1>(v1) } );
}
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) || BOOST_WORKAROUND( BOOST_MSVC, < 1920 )
@@ -2060,31 +2075,31 @@ template<class F, class A> bind_front_<F, A> bind_front( F&& f, A&& a )
return bind_front_<F, A>{ std::forward<F>(f), std::forward<A>(a) };
}
template<class F, class V1, class V2> struct visit_L2
template<class R, class F, class V1, class V2> struct visit_L2
{
F&& f;
V1&& v1;
V2&& v2;
template<class I> auto operator()( I ) const -> Vret<F, V1, V2>
template<class I> auto operator()( I ) const -> Vret<R, F, V1, V2>
{
auto f2 = bind_front( std::forward<F>(f), unsafe_get<I::value>( std::forward<V1>(v1) ) );
return visit( f2, std::forward<V2>(v2) );
return visit<R>( f2, std::forward<V2>(v2) );
}
};
} // namespace detail
template<class F, class V1, class V2> constexpr auto visit( F&& f, V1&& v1, V2&& v2 ) -> detail::Vret<F, V1, V2>
template<class R = detail::deduced, class F, class V1, class V2> constexpr auto visit( F&& f, V1&& v1, V2&& v2 ) -> detail::Vret<R, F, V1, V2>
{
return mp11::mp_with_index<detail::variant_base_size<V1>>( v1.index(), detail::visit_L2<F, V1, V2>{ std::forward<F>(f), std::forward<V1>(v1), std::forward<V2>(v2) } );
return mp11::mp_with_index<detail::variant_base_size<V1>>( v1.index(), detail::visit_L2<R, F, V1, V2>{ std::forward<F>(f), std::forward<V1>(v1), std::forward<V2>(v2) } );
}
namespace detail
{
template<class F, class V1, class V2, class V3> struct visit_L3
template<class R, class F, class V1, class V2, class V3> struct visit_L3
{
F&& f;
@@ -2092,24 +2107,24 @@ template<class F, class V1, class V2, class V3> struct visit_L3
V2&& v2;
V3&& v3;
template<class I> auto operator()( I ) const -> Vret<F, V1, V2, V3>
template<class I> auto operator()( I ) const -> Vret<R, F, V1, V2, V3>
{
auto f2 = bind_front( std::forward<F>(f), unsafe_get<I::value>( std::forward<V1>(v1) ) );
return visit( f2, std::forward<V2>(v2), std::forward<V3>(v3) );
return visit<R>( f2, std::forward<V2>(v2), std::forward<V3>(v3) );
}
};
} // namespace detail
template<class F, class V1, class V2, class V3> constexpr auto visit( F&& f, V1&& v1, V2&& v2, V3&& v3 ) -> detail::Vret<F, V1, V2, V3>
template<class R = detail::deduced, class F, class V1, class V2, class V3> constexpr auto visit( F&& f, V1&& v1, V2&& v2, V3&& v3 ) -> detail::Vret<R, F, V1, V2, V3>
{
return mp11::mp_with_index<detail::variant_base_size<V1>>( v1.index(), detail::visit_L3<F, V1, V2, V3>{ std::forward<F>(f), std::forward<V1>(v1), std::forward<V2>(v2), std::forward<V3>(v3) } );
return mp11::mp_with_index<detail::variant_base_size<V1>>( v1.index(), detail::visit_L3<R, F, V1, V2, V3>{ std::forward<F>(f), std::forward<V1>(v1), std::forward<V2>(v2), std::forward<V3>(v3) } );
}
namespace detail
{
template<class F, class V1, class V2, class V3, class V4> struct visit_L4
template<class R, class F, class V1, class V2, class V3, class V4> struct visit_L4
{
F&& f;
@@ -2118,28 +2133,28 @@ template<class F, class V1, class V2, class V3, class V4> struct visit_L4
V3&& v3;
V4&& v4;
template<class I> auto operator()( I ) const -> Vret<F, V1, V2, V3, V4>
template<class I> auto operator()( I ) const -> Vret<R, F, V1, V2, V3, V4>
{
auto f2 = bind_front( std::forward<F>(f), unsafe_get<I::value>( std::forward<V1>(v1) ) );
return visit( f2, std::forward<V2>(v2), std::forward<V3>(v3), std::forward<V4>(v4) );
return visit<R>( f2, std::forward<V2>(v2), std::forward<V3>(v3), std::forward<V4>(v4) );
}
};
} // namespace detail
template<class F, class V1, class V2, class V3, class V4> constexpr auto visit( F&& f, V1&& v1, V2&& v2, V3&& v3, V4&& v4 ) -> detail::Vret<F, V1, V2, V3, V4>
template<class R = detail::deduced, class F, class V1, class V2, class V3, class V4> constexpr auto visit( F&& f, V1&& v1, V2&& v2, V3&& v3, V4&& v4 ) -> detail::Vret<R, F, V1, V2, V3, V4>
{
return mp11::mp_with_index<detail::variant_base_size<V1>>( v1.index(), detail::visit_L4<F, V1, V2, V3, V4>{ std::forward<F>(f), std::forward<V1>(v1), std::forward<V2>(v2), std::forward<V3>(v3), std::forward<V4>(v4) } );
return mp11::mp_with_index<detail::variant_base_size<V1>>( v1.index(), detail::visit_L4<R, F, V1, V2, V3, V4>{ std::forward<F>(f), std::forward<V1>(v1), std::forward<V2>(v2), std::forward<V3>(v3), std::forward<V4>(v4) } );
}
#else
template<class F, class V1, class V2, class... V> constexpr auto visit( F&& f, V1&& v1, V2&& v2, V&&... v ) -> detail::Vret<F, V1, V2, V...>
template<class R = detail::deduced, class F, class V1, class V2, class... V> constexpr auto visit( F&& f, V1&& v1, V2&& v2, V&&... v ) -> detail::Vret<R, F, V1, V2, V...>
{
return mp11::mp_with_index<detail::variant_base_size<V1>>( v1.index(), [&]( auto I ){
auto f2 = [&]( auto&&... a ){ return std::forward<F>(f)( detail::unsafe_get<I.value>( std::forward<V1>(v1) ), std::forward<decltype(a)>(a)... ); };
return visit( f2, std::forward<V2>(v2), std::forward<V>(v)... );
return visit<R>( f2, std::forward<V2>(v2), std::forward<V>(v)... );
});
}