forked from boostorg/variant2
Add support for visit<R>
This commit is contained in:
@ -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)... );
|
||||
|
||||
});
|
||||
}
|
||||
|
@ -114,3 +114,5 @@ run variant_special.cpp ;
|
||||
run variant_visit_derived.cpp ;
|
||||
|
||||
run variant_many_types.cpp ;
|
||||
|
||||
run variant_visit_r.cpp ;
|
||||
|
98
test/variant_visit_r.cpp
Normal file
98
test/variant_visit_r.cpp
Normal file
@ -0,0 +1,98 @@
|
||||
|
||||
// Copyright 2017 Peter Dimov.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
//
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning( disable: 4244 ) // conversion from float to int, possible loss of data
|
||||
#endif
|
||||
|
||||
#include <boost/variant2/variant.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
using namespace boost::variant2;
|
||||
|
||||
struct F1
|
||||
{
|
||||
template<class T1> T1 operator()( T1 t1 ) const
|
||||
{
|
||||
return t1;
|
||||
}
|
||||
};
|
||||
|
||||
struct F2
|
||||
{
|
||||
template<class T1, class T2> auto operator()( T1 t1, T2 t2 ) const -> decltype( t1 + t2 )
|
||||
{
|
||||
return t1 + t2;
|
||||
}
|
||||
};
|
||||
|
||||
struct F3
|
||||
{
|
||||
template<class T1, class T2, class T3> auto operator()( T1 t1, T2 t2, T3 t3 ) const -> decltype( t1 + t2 + t3 )
|
||||
{
|
||||
return t1 + t2 + t3;
|
||||
}
|
||||
};
|
||||
|
||||
struct F4
|
||||
{
|
||||
template<class T1, class T2, class T3, class T4> auto operator()( T1 t1, T2 t2, T3 t3, T4 t4 ) const -> decltype( t1 + t2 + t3 + t4 )
|
||||
{
|
||||
return t1 + t2 + t3 + t4;
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
BOOST_TEST_EQ( (visit<int>( []{ return 3.14f; } )), 3 );
|
||||
}
|
||||
|
||||
{
|
||||
variant<int, float> v( 1 );
|
||||
|
||||
BOOST_TEST_EQ( visit<int>( F1(), v ), 1 );
|
||||
BOOST_TEST_EQ( visit<float>( F1(), v ), 1.0f );
|
||||
}
|
||||
|
||||
{
|
||||
variant<int, float> const v( 3.14f );
|
||||
|
||||
BOOST_TEST_EQ( visit<int>( F1(), v ), 3 );
|
||||
BOOST_TEST_EQ( visit<float>( F1(), v ), 3.14f );
|
||||
}
|
||||
|
||||
{
|
||||
variant<int, float> v1( 1 );
|
||||
variant<int, float> const v2( 3.14f );
|
||||
|
||||
BOOST_TEST_EQ( visit<int>( F2(), v1, v2 ), 4 );
|
||||
BOOST_TEST_EQ( visit<float>( F2(), v1, v2 ), 1 + 3.14f );
|
||||
}
|
||||
|
||||
{
|
||||
variant<int, float, double> v1( 1 );
|
||||
variant<int, float, double> const v2( 3.14f );
|
||||
variant<int, float, double> v3( 6.28 );
|
||||
|
||||
BOOST_TEST_EQ( visit<int>( F3(), v1, v2, v3 ), 10 );
|
||||
BOOST_TEST_EQ( visit<float>( F3(), v1, v2, v3 ), static_cast<float>( 1 + 3.14f + 6.28 ) );
|
||||
}
|
||||
|
||||
{
|
||||
variant<int, float, double, char> v1( 1 );
|
||||
variant<int, float, double, char> const v2( 3.14f );
|
||||
variant<int, float, double, char> v3( 6.28 );
|
||||
variant<int, float, double, char> const v4( 'A' );
|
||||
|
||||
BOOST_TEST_EQ( visit<int>( F4(), v1, v2, v3, v4 ), 10 + 'A' );
|
||||
BOOST_TEST_EQ( visit<float>( F4(), v1, v2, v3, v4 ), static_cast<float>( 1 + 3.14f + 6.28 + 'A' ) );
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
Reference in New Issue
Block a user