forked from boostorg/variant2
Implement visit
This commit is contained in:
@ -1063,11 +1063,87 @@ template<class... T> constexpr bool operator>=( variant<T...> const & v, variant
|
||||
}
|
||||
|
||||
// visitation
|
||||
template<class Visitor, class... Variants> constexpr void visit( Visitor&&, Variants&&... );
|
||||
template<class F> constexpr auto visit( F&& f ) -> decltype(std::forward<F>(f)())
|
||||
{
|
||||
return std::forward<F>(f)();
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class T> using remove_cv_ref = std::remove_cv_t<std::remove_reference_t<T>>;
|
||||
|
||||
template<class F> struct Qret
|
||||
{
|
||||
template<class... T> using fn = decltype( std::declval<F>()( std::declval<T>()... ) );
|
||||
};
|
||||
|
||||
template<class L> using front_if_same = mp_if<mp_apply<mp_same, L>, mp_front<L>>;
|
||||
|
||||
template<class F, class... V> using Vret = front_if_same<mp_product_q<Qret<F>, remove_cv_ref<V>...>>;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<class F, class V1> constexpr auto visit( F&& f, V1&& v1 ) -> variant2::detail::Vret<F, V1>
|
||||
{
|
||||
return mp_for_index<mp_size<variant2::detail::remove_cv_ref<V1>>>( v1.index(), [&]( auto I ){
|
||||
|
||||
return std::forward<F>(f)( get<I>( std::forward<V1>(v1) ) );
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
#if BOOST_WORKAROUND( BOOST_MSVC, <= 1910 )
|
||||
|
||||
template<class F, class V1, class V2> constexpr auto visit( F&& f, V1&& v1, V2&& v2 ) -> variant2::detail::Vret<F, V1, V2>
|
||||
{
|
||||
return mp_for_index<mp_size<variant2::detail::remove_cv_ref<V1>>>( v1.index(), [&]( auto I ){
|
||||
|
||||
auto f2 = [&]( auto&&... a ){ return std::forward<F>(f)( get<I.value>( std::forward<V1>(v1) ), std::forward<decltype(a)>(a)... ); };
|
||||
return visit( f2, std::forward<V2>(v2) );
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
template<class F, class V1, class V2, class V3> constexpr auto visit( F&& f, V1&& v1, V2&& v2, V3&& v3 ) -> variant2::detail::Vret<F, V1, V2, V3>
|
||||
{
|
||||
return mp_for_index<mp_size<variant2::detail::remove_cv_ref<V1>>>( v1.index(), [&]( auto I ){
|
||||
|
||||
auto f2 = [&]( auto&&... a ){ return std::forward<F>(f)( get<I.value>( std::forward<V1>(v1) ), std::forward<decltype(a)>(a)... ); };
|
||||
return visit( f2, std::forward<V2>(v2), std::forward<V3>(v3) );
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
template<class F, class V1, class V2, class V3, class V4> constexpr auto visit( F&& f, V1&& v1, V2&& v2, V3&& v3, V4&& v4 ) -> variant2::detail::Vret<F, V1, V2, V3, V4>
|
||||
{
|
||||
return mp_for_index<mp_size<variant2::detail::remove_cv_ref<V1>>>( v1.index(), [&]( auto I ){
|
||||
|
||||
auto f2 = [&]( auto&&... a ){ return std::forward<F>(f)( get<I.value>( std::forward<V1>(v1) ), std::forward<decltype(a)>(a)... ); };
|
||||
return visit( f2, 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 ) -> variant2::detail::Vret<F, V1, V2, V...>
|
||||
{
|
||||
return mp_for_index<mp_size<variant2::detail::remove_cv_ref<V1>>>( v1.index(), [&]( auto I ){
|
||||
|
||||
auto f2 = [&]( auto&&... a ){ return std::forward<F>(f)( get<I.value>( std::forward<V1>(v1) ), std::forward<decltype(a)>(a)... ); };
|
||||
return visit( f2, std::forward<V2>(v2), std::forward<V>(v)... );
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// specialized algorithms
|
||||
template<class... T, class E = std::enable_if_t<mp_all<std::is_move_constructible<T>..., variant2::detail::is_swappable<T>...>::value>>
|
||||
void swap( variant<T...> & v, variant<T...> & w ) noexcept( noexcept(v.swap(w)) )
|
||||
template<class... T,
|
||||
class E = std::enable_if_t<mp_all<std::is_move_constructible<T>..., variant2::detail::is_swappable<T>...>::value>>
|
||||
void swap( variant<T...> & v, variant<T...> & w )
|
||||
noexcept( noexcept(v.swap(w)) )
|
||||
{
|
||||
v.swap( w );
|
||||
}
|
||||
|
@ -37,3 +37,4 @@ run variant_emplace_type.cpp : : : $(REQ) ;
|
||||
run variant_swap.cpp : : : $(REQ) ;
|
||||
run variant_eq_ne.cpp : : : $(REQ) ;
|
||||
run variant_destroy.cpp : : : $(REQ) ;
|
||||
run variant_visit.cpp : : : $(REQ) ;
|
||||
|
91
test/variant_visit.cpp
Normal file
91
test/variant_visit.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
|
||||
// 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
|
||||
|
||||
#include <boost/variant2/variant.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test_trait.hpp>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
|
||||
using namespace boost::variant2;
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
variant<int> v( 1 );
|
||||
|
||||
BOOST_TEST_EQ( (visit( []( auto x ){ return x; }, v )), 1 );
|
||||
|
||||
visit( []( auto x ){ BOOST_TEST_EQ( x, 1 ); }, v );
|
||||
visit( []( auto x ){ BOOST_TEST_EQ( x, 1 ); }, std::move(v) );
|
||||
}
|
||||
|
||||
{
|
||||
variant<int> const v( 2 );
|
||||
|
||||
BOOST_TEST_EQ( (visit( []( auto x ){ return x; }, v )), 2 );
|
||||
|
||||
visit( []( auto x ){ BOOST_TEST_EQ( x, 2 ); }, v );
|
||||
visit( []( auto x ){ BOOST_TEST_EQ( x, 2 ); }, std::move(v) );
|
||||
}
|
||||
|
||||
{
|
||||
variant<int const> v( 3 );
|
||||
|
||||
BOOST_TEST_EQ( (visit( []( auto x ){ return x; }, v )), 3 );
|
||||
|
||||
visit( []( auto x ){ BOOST_TEST_EQ( x, 3 ); }, v );
|
||||
visit( []( auto x ){ BOOST_TEST_EQ( x, 3 ); }, std::move(v) );
|
||||
}
|
||||
|
||||
{
|
||||
variant<int const> const v( 4 );
|
||||
|
||||
BOOST_TEST_EQ( (visit( []( auto x ){ return x; }, v )), 4 );
|
||||
|
||||
visit( []( auto x ){ BOOST_TEST_EQ( x, 4 ); }, v );
|
||||
visit( []( auto x ){ BOOST_TEST_EQ( x, 4 ); }, std::move(v) );
|
||||
}
|
||||
|
||||
{
|
||||
variant<int, float> v1( 1 );
|
||||
variant<int, float> const v2( 3.14f );
|
||||
|
||||
BOOST_TEST_EQ( (visit( []( auto x1, auto x2 ){ return (int)(x1 * 1000) + (int)(x2 * 100); }, v1, v2 )), 1314 );
|
||||
|
||||
visit( []( auto x1, auto x2 ){ BOOST_TEST_EQ( x1, 1 ); BOOST_TEST_EQ( x2, 3.14f ); }, v1, v2 );
|
||||
visit( []( auto x1, auto x2 ){ BOOST_TEST_EQ( x1, 1 ); BOOST_TEST_EQ( x2, 3.14f ); }, std::move(v1), std::move(v2) );
|
||||
}
|
||||
|
||||
{
|
||||
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( []( auto x1, auto x2, auto x3 ){ return (int)(x1 * 100) * 1000000 + (int)(x2 * 100) * 1000 + (int)(x3 * 100); }, v1, v2, v3 )), 100314628 );
|
||||
|
||||
visit( []( auto x1, auto x2, auto x3 ){ BOOST_TEST_EQ( x1, 1 ); BOOST_TEST_EQ( x2, 3.14f ); BOOST_TEST_EQ( x3, 6.28 ); }, v1, v2, v3 );
|
||||
visit( []( auto x1, auto x2, auto x3 ){ BOOST_TEST_EQ( x1, 1 ); BOOST_TEST_EQ( x2, 3.14f ); BOOST_TEST_EQ( x3, 6.28 ); }, std::move(v1), std::move(v2), std::move(v3) );
|
||||
}
|
||||
|
||||
{
|
||||
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( []( auto x1, auto x2, auto x3, auto x4 ){ return (long long)(x1 * 100) * 100000000 + (long long)(x2 * 100) * 100000 + (long long)(x3 * 10000) + (int)x4; }, v1, v2, v3, v4 )), 10031462800 + 'A' );
|
||||
|
||||
visit( []( auto x1, auto x2, auto x3, auto x4 ){ BOOST_TEST_EQ( x1, 1 ); BOOST_TEST_EQ( x2, 3.14f ); BOOST_TEST_EQ( x3, 6.28 ); BOOST_TEST_EQ( x4, 'A' ); }, v1, v2, v3, v4 );
|
||||
visit( []( auto x1, auto x2, auto x3, auto x4 ){ BOOST_TEST_EQ( x1, 1 ); BOOST_TEST_EQ( x2, 3.14f ); BOOST_TEST_EQ( x3, 6.28 ); BOOST_TEST_EQ( x4, 'A' ); }, std::move(v1), std::move(v2), std::move(v3), std::move(v4) );
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
Reference in New Issue
Block a user