From db565aaa73f2f218c6e369282cb3095db9d1253d Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Thu, 1 Jun 2017 01:48:38 +0300 Subject: [PATCH] Implement visit --- include/boost/variant2/variant.hpp | 82 ++++++++++++++++++++++++++- test/Jamfile | 1 + test/variant_visit.cpp | 91 ++++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+), 3 deletions(-) create mode 100644 test/variant_visit.cpp diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp index 0f64f42..4ce586e 100644 --- a/include/boost/variant2/variant.hpp +++ b/include/boost/variant2/variant.hpp @@ -1063,11 +1063,87 @@ template constexpr bool operator>=( variant const & v, variant } // visitation -template constexpr void visit( Visitor&&, Variants&&... ); +template constexpr auto visit( F&& f ) -> decltype(std::forward(f)()) +{ + return std::forward(f)(); +} + +namespace detail +{ + +template using remove_cv_ref = std::remove_cv_t>; + +template struct Qret +{ + template using fn = decltype( std::declval()( std::declval()... ) ); +}; + +template using front_if_same = mp_if, mp_front>; + +template using Vret = front_if_same, remove_cv_ref...>>; + +} // namespace detail + +template constexpr auto visit( F&& f, V1&& v1 ) -> variant2::detail::Vret +{ + return mp_for_index>>( v1.index(), [&]( auto I ){ + + return std::forward(f)( get( std::forward(v1) ) ); + + }); +} + +#if BOOST_WORKAROUND( BOOST_MSVC, <= 1910 ) + +template constexpr auto visit( F&& f, V1&& v1, V2&& v2 ) -> variant2::detail::Vret +{ + return mp_for_index>>( v1.index(), [&]( auto I ){ + + auto f2 = [&]( auto&&... a ){ return std::forward(f)( get( std::forward(v1) ), std::forward(a)... ); }; + return visit( f2, std::forward(v2) ); + + }); +} + +template constexpr auto visit( F&& f, V1&& v1, V2&& v2, V3&& v3 ) -> variant2::detail::Vret +{ + return mp_for_index>>( v1.index(), [&]( auto I ){ + + auto f2 = [&]( auto&&... a ){ return std::forward(f)( get( std::forward(v1) ), std::forward(a)... ); }; + return visit( f2, std::forward(v2), std::forward(v3) ); + + }); +} + +template constexpr auto visit( F&& f, V1&& v1, V2&& v2, V3&& v3, V4&& v4 ) -> variant2::detail::Vret +{ + return mp_for_index>>( v1.index(), [&]( auto I ){ + + auto f2 = [&]( auto&&... a ){ return std::forward(f)( get( std::forward(v1) ), std::forward(a)... ); }; + return visit( f2, std::forward(v2), std::forward(v3), std::forward(v4) ); + + }); +} + +#else + +template constexpr auto visit( F&& f, V1&& v1, V2&& v2, V&&... v ) -> variant2::detail::Vret +{ + return mp_for_index>>( v1.index(), [&]( auto I ){ + + auto f2 = [&]( auto&&... a ){ return std::forward(f)( get( std::forward(v1) ), std::forward(a)... ); }; + return visit( f2, std::forward(v2), std::forward(v)... ); + + }); +} + +#endif // specialized algorithms -template..., variant2::detail::is_swappable...>::value>> -void swap( variant & v, variant & w ) noexcept( noexcept(v.swap(w)) ) +template..., variant2::detail::is_swappable...>::value>> +void swap( variant & v, variant & w ) + noexcept( noexcept(v.swap(w)) ) { v.swap( w ); } diff --git a/test/Jamfile b/test/Jamfile index 323ec4d..ab1fd9a 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -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) ; diff --git a/test/variant_visit.cpp b/test/variant_visit.cpp new file mode 100644 index 0000000..5058e3e --- /dev/null +++ b/test/variant_visit.cpp @@ -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 +#include +#include +#include +#include +#include +#include + +using namespace boost::variant2; + +int main() +{ + { + variant 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 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 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 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 v1( 1 ); + variant 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 v1( 1 ); + variant const v2( 3.14f ); + variant 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 v1( 1 ); + variant const v2( 3.14f ); + variant v3( 6.28 ); + variant 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(); +}