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 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
|
} // 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)();
|
return std::forward<F>(f)();
|
||||||
}
|
}
|
||||||
@@ -2021,12 +2036,12 @@ template<class F> constexpr auto visit( F&& f ) -> decltype(std::forward<F>(f)()
|
|||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
|
|
||||||
template<class F, class V1> struct visit_L1
|
template<class R, class F, class V1> struct visit_L1
|
||||||
{
|
{
|
||||||
F&& f;
|
F&& f;
|
||||||
V1&& v1;
|
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) ) );
|
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
|
} // 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 )
|
#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) };
|
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;
|
F&& f;
|
||||||
|
|
||||||
V1&& v1;
|
V1&& v1;
|
||||||
V2&& v2;
|
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) ) );
|
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
|
} // 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
|
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;
|
F&& f;
|
||||||
|
|
||||||
@@ -2092,24 +2107,24 @@ template<class F, class V1, class V2, class V3> struct visit_L3
|
|||||||
V2&& v2;
|
V2&& v2;
|
||||||
V3&& v3;
|
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) ) );
|
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
|
} // 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
|
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;
|
F&& f;
|
||||||
|
|
||||||
@@ -2118,28 +2133,28 @@ template<class F, class V1, class V2, class V3, class V4> struct visit_L4
|
|||||||
V3&& v3;
|
V3&& v3;
|
||||||
V4&& v4;
|
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) ) );
|
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
|
} // 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
|
#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 ){
|
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)... ); };
|
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_visit_derived.cpp ;
|
||||||
|
|
||||||
run variant_many_types.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