diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp index f262f0e..5b319b4 100644 --- a/include/boost/variant2/variant.hpp +++ b/include/boost/variant2/variant.hpp @@ -81,22 +81,22 @@ template using variant_alternative_t = typename variant_ namespace detail { - template using var_alt_t = mp_invoke>; + template using var_alt_impl = mp_invoke>; } // namespace detail template struct variant_alternative { }; -template struct variant_alternative: mp_defer< variant2::detail::var_alt_t, mp_size_t, T, mp_quote> +template struct variant_alternative: mp_defer< variant2::detail::var_alt_impl, mp_size_t, T, mp_quote> { }; -template struct variant_alternative: mp_defer< variant2::detail::var_alt_t, mp_size_t, T, mp_quote> +template struct variant_alternative: mp_defer< variant2::detail::var_alt_impl, mp_size_t, T, mp_quote> { }; -template struct variant_alternative: mp_defer< variant2::detail::var_alt_t, mp_size_t, T, mp_quote> +template struct variant_alternative: mp_defer< variant2::detail::var_alt_impl, mp_size_t, T, mp_quote> { }; @@ -1065,16 +1065,9 @@ template constexpr bool operator>=( variant const & v, variant } // visitation -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()... ) ); @@ -1082,13 +1075,41 @@ template struct Qret template using front_if_same = mp_if, mp_front>; -template using Vret = front_if_same, remove_cv_ref...>>; +template using var_size = variant_size>; + +template>> using apply_cv_ref_ = mp_if, T&, T>; + +#if BOOST_WORKAROUND( BOOST_MSVC, <= 1910 ) + +template struct apply_cv_ref_impl +{ + template using _f = apply_cv_ref_; + + using L = mp_iota>; + + using type = mp_transform<_f, L>; +}; + +template using apply_cv_ref = typename apply_cv_ref_impl::type; + +#else + +template using apply_cv_ref = mp_transform_q, mp_iota>>; + +#endif + +template using Vret = front_if_same, apply_cv_ref...>>; } // namespace detail +template constexpr auto visit( F&& f ) -> decltype(std::forward(f)()) +{ + return std::forward(f)(); +} + template constexpr auto visit( F&& f, V1&& v1 ) -> variant2::detail::Vret { - return mp_for_index>>( v1.index(), [&]( auto I ){ + return mp_for_index>( v1.index(), [&]( auto I ){ return std::forward(f)( get( std::forward(v1) ) ); @@ -1099,7 +1120,7 @@ template constexpr auto visit( F&& f, V1&& v1 ) -> variant2:: template constexpr auto visit( F&& f, V1&& v1, V2&& v2 ) -> variant2::detail::Vret { - return mp_for_index>>( v1.index(), [&]( auto I ){ + 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) ); @@ -1109,7 +1130,7 @@ template constexpr auto visit( F&& f, V1&& v1, V2&& template constexpr auto visit( F&& f, V1&& v1, V2&& v2, V3&& v3 ) -> variant2::detail::Vret { - return mp_for_index>>( v1.index(), [&]( auto I ){ + 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) ); @@ -1119,7 +1140,7 @@ template constexpr auto visit( F&& f, V1& 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 ){ + 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) ); @@ -1131,7 +1152,7 @@ template constexpr auto visit( template constexpr auto visit( F&& f, V1&& v1, V2&& v2, V&&... v ) -> variant2::detail::Vret { - return mp_for_index>>( v1.index(), [&]( auto I ){ + 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)... ); diff --git a/test/variant_visit.cpp b/test/variant_visit.cpp index 5058e3e..98fdb29 100644 --- a/test/variant_visit.cpp +++ b/test/variant_visit.cpp @@ -7,6 +7,7 @@ // http://www.boost.org/LICENSE_1_0.txt #include +#include #include #include #include @@ -15,6 +16,19 @@ #include using namespace boost::variant2; +using boost::mp11::mp_size_t; + +struct X +{ +}; + +struct F +{ + mp_size_t<1> operator()( X& ) const; + mp_size_t<2> operator()( X const& ) const; + mp_size_t<3> operator()( X&& ) const; + mp_size_t<4> operator()( X const&& ) const; +}; int main() { @@ -84,7 +98,17 @@ int main() 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) ); + 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) ); + } + + { + variant v; + variant const cv; + + BOOST_TEST_EQ( decltype(visit(F{}, v))::value, 1 ); + BOOST_TEST_EQ( decltype(visit(F{}, cv))::value, 2 ); + BOOST_TEST_EQ( decltype(visit(F{}, std::move(v)))::value, 3 ); + BOOST_TEST_EQ( decltype(visit(F{}, std::move(cv)))::value, 4 ); } return boost::report_errors();